屏幕数据无限滚动,鼠标移入滚动停止,鼠标移出滚动继续的业务场景,出境率还是非常高的,直接上代码,复制粘贴到一个
.vue
文件即可看运行。
1、template
<template>
<div class="list-wrap" ref="listWrap" @mouseenter="enterScrollArea" @mouseleave="leaveScrollArea">
<div v-for="(item, index) in list" :ref="'item' + index" :key="index" class="item">
<div class="item-name">{{ item.name }}</div>
<div class="item-info">{{ item.info }}</div>
<div class="item-time">{{ item.time }}</div>
</div>
</div>
</template>
2、script
<script>
export default {
data() {
return {
list: [], // 当前页面滚动的数据,假设有10条;自动滚动时,会稳定在20条;鼠标移入时,变为10条;
defaultList: [], // 10条数据,鼠标移入时,会将中间截取后的数据组成新的默认数据
groupCount: 0, // 当前共有几组defaultList数据,组数 - 1
isMouseenter: false, // 鼠标是否移入了滚动区域
timer: "", // 轮播图定时器
childrenDomHeight: 0, // 子元素总高度
heightScale: [0], // 高度刻度数组
heightList: [], // 高度数组
curIndex: 0, // 鼠标移入时是第几个元素在顶部
};
},
created() {
// 造假数据
for (let i = 0; i < 10; i++) {
this.defaultList.push({
name: `标题${i + 1}`,
info: new Array(50).fill("好").join(""),
time: "2023-01-01",
});
}
// 为滚动数据赋值
this.list = [...this.defaultList];
},
mounted() {
let _this = this;
// 获取当前滚动的实例
this.listWrap = this.$refs.listWrap;
// 定义每个子元素交界处的刻度值数组,和高度数组
for (let i = 0; i < 10; i++) {
let h = this.$refs[`item${i}`][0].clientHeight;
this.heightScale.push(this.heightScale[this.heightScale.length - 1] + h);
this.heightList.push(h);
this.childrenDomHeight += h;
}
// 当前容器高度
let listWrapHeight = this.listWrap.clientHeight;
// 最大可滚动高度
let maximumScrollH = this.childrenDomHeight - listWrapHeight;
// 监听变化,当滚动的高度触底,并且鼠标在滚动区域外部时进行轮播效果的实现
this.listWrap.addEventListener("scroll", function (e) {
if (
_this.listWrap.scrollTop >=
_this.groupCount * _this.childrenDomHeight + maximumScrollH &&
!this.isMouseenter
) {
_this.groupCount++;
_this.list = _this.list.concat(_this.defaultList);
// 当数组长度变成30时
if (_this.list.length > 20) {
// 从第11个元素开始取到结尾,保持在20条数据;
_this.list = _this.list.slice(10);
// 将当前滚动区域滚动1个最大可滚动距离
_this.listWrap.scrollTop = maximumScrollH;
// 设置当前组数为1
_this.groupCount = 1;
}
}
});
// 让滚动区域进行滚动
this.timer = setInterval(() => {
_this.listWrap.scrollTop += 1;
}, 20);
},
methods: {
enterScrollArea() {
// 鼠标移入
this.isMouseenter = true;
// 清空定时器
clearInterval(this.timer);
// 找到当前是第几个元素在顶部
let currH = this.listWrap.scrollTop;
for (let i = 0; i < this.heightScale.length; i++) {
if (this.heightScale[i] < currH && currH < this.heightScale[i + 1]) {
this.curIndex = i;
}
}
// 取出从第this.curIndex开始的10个元素,头部删掉前this.curIndex个,尾部删掉10-this.curIndex个,并且组成一个新的数组
this.list = this.list.slice(this.curIndex, this.curIndex + 10);
let leftArr = this.defaultList.slice(0, this.curIndex);
let rightArr = this.defaultList.slice(this.curIndex);
this.defaultList = [...rightArr, ...leftArr];
// 新截取数组列表,把其位置滚动到和鼠标移入时相同位置
this.listWrap.scrollTop =
this.heightList[this.curIndex] +
(this.listWrap.scrollTop - this.heightScale[this.curIndex + 1]);
},
leaveScrollArea() {
// 鼠标移出时,将其长度扩展为20条数据,并进行定时器的开启
this.list = this.list.concat([...this.defaultList]);
this.timer = setInterval(() => {
this.listWrap.scrollTop += 1;
}, 20);
},
},
};
</script>
3、style
<style>
.list-wrap {
margin: 100px;
height: 600px;
width: 500px;
border: 1px solid #aaa;
border-radius: 10px;
overflow-y: scroll;
}
.list-wrap::-webkit-scrollbar {
display: none;
}
.item {
padding: 10px;
}
</style>
总结
无限滚动实现主要是借助了setInterval
定时器来实现。需要注意的是自动滚动触底时数组动态无限拼接。鼠标移入时中间数组的截取,鼠标移入时获取当前是第几个元素置顶,并从当前位置开始进行数组的截取,和滚动位置的重新赋值。鼠标移出时,为数组拼接新的defaultList
数组,让其维持在20
条数据。