vue2.0无限滚动

1,608 阅读1分钟

屏幕数据无限滚动,鼠标移入滚动停止,鼠标移出滚动继续的业务场景,出境率还是非常高的,直接上代码,复制粘贴到一个.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条数据。