在工作中,碰到PC端类似聊天框,鼠标向上滚动,触顶时分页获取数据;但是将接口获得的数据连接到循环数组数据前面时,由于数据变化,滚动条会直接滚动到最顶端,显然这个效果不友好。最好的效果就是,页面会停留在上次查看的位置。
目前问题是解决了,但是是以vue2的基础上解决的,但是vue3也是可以完全使用的。一开时写这个需求时,感觉我写的不太好,因为我把消息输入框和消息渲染框写成了两个子组件,而且项目还是vue3,显然加大了编写代码的难度。
组件通信太复杂的话,还是写在一个页面好;不然难度过于复杂。代码就在下面,相信可以为你所用
javascript
<template>
<div class="scroll-container" @wheel="handleScroll">
<div v-for="(item, index) in items" :key="index" class="item">
{{ item.num }}
</div>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{
num: 1
},
{
num: 2
},
{
num: 3
},
{
num: 4
},
{
num: 5
},
{
num: 6
},
{
num: 7
},
], // 初始数据
isLoading: false,
lastScrollTop: 0, // 记录上次滚动位置
};
},
methods: {
handleScroll(event) {
if (this.isLoading) return;
const scrollDiv = document.getElementsByClassName('scroll-container')[0]
const container = event.target;
if (event.deltaY < 0) {
console.log(container.scrollTop);
if (scrollDiv.scrollTop == 0) {
console.log('滚动');
this.isLoading = true
this.loadMore();
}
}
},
loadMore() {
// 模拟异步加载数据
setTimeout(() => {
this.items.unshift(
{
num: '12'
},
{
num: '13'
},
{
num: '14'
},
{
num: '15'
},
{
num: '16'
},
{
num: '17'
},
{
num: '18'
},
{
num: '19'
},
{
num: '20'
},
);
this.$nextTick(this.scrollToLastPosition); // 数据更新后滚动到上次位置
this.isLoading = false;
}, 1000);
},
scrollToLastPosition() {
const container = document.getElementsByClassName('scroll-container')[0];
const items = document.getElementsByClassName('item')
container.scrollTop = items[10].offsetTop;
}
},
};
</script>
<style>
.scroll-container {
width: 600px;
height: 800px;
/* 设置一个固定高度 */
overflow-y: auto;
position: relative;
}
.item {
width: 100%;
height: 200px;
border: 1px solid #ccc;
/* 每个item的高度 */
}
.loader {
text-align: center;
margin-top: 10px;
}
</style>
解决的关键
数据更新时后,要获取数据更新前,位于滚动条最顶端的元素距离父元素里偏移距离,当然父元素要设置相对定位,这样才能获取目标元素的的偏移量offsetTop,也就是父元素滚动条要滚动的距离。这里设置的是第十个元素的偏移量,这里可以设置为接口返回的数据的长度。再设置滚动的父元素的scrollTop为获取的元素偏移量就可以了。