vue封装实现自动循环滚动的列表

 更新时间:2023年09月14日 11:15:59   作者:HXY999  
在做数据大屏开发的过程中,经常出现需要对列表进行自动滚动的需求,所以本文就来为大家介绍一下如何利用vue封装一个自动循环滚动的列表吧

前言

在做数据大屏开发的过程中,经常出现需要对列表进行自动滚动的需求,为了个性化的实现各种需求,就封装了一个函数方法

解决方案

  • 生成一个父元素,并给其固定的高度,通过$refs获取并赋值给container变量
  • 获取一些关于container和其子元素的信息,如父容器高度(parentHeight)、滚动高度(scrollHeight)、第一个子元素的高度(childHeight)、子元素数量(childCount)、最大高度(maxHeight)、当前滚动位置(toHeight)和当前子元素索引(current),并初始化一个名为timer的计时器。
  • 定义一个名为scrollCore的函数,该函数用于实现滚动效果。
  • scrollCore函数中检查如果scrollHeight大于parentHeight,则创建一个定时器,以便每隔一段时间执行一次滚动操作。
  • 在定时器中,scrollCore函数中逐渐增加容器的scrollTop属性,从而实现滚动效果。

一、匀速自动滚动,并实现方法可对多个列表复用

思路:通过对ref的命名,来实现在方法中使用for循环来对多个列表生效

<template>
<div>
    <ul class="shiJianGaoJingContent_right" ref="scroll0">
        <li class="gaojing_info_list" v-for="(item, index) in scrollInfoList" :key="index">
        </li>
    </ul> 
</div>
</template>
<script>
export default {
  data() {
    return {
      scrollInfoList:[],
    };
  },
  methods: {
  // 列表自动滚动
    scrollFn() {
      let dataList = [];
      for (let i = 0; i < 1; i++) {
        let container = this.$refs["scroll" + i];
        let parentHeight = container.offsetHeight || 0;
        let scrollHeight = container.scrollHeight;
        let childHeight = container.firstChild.offsetHeight;
        let childCount = container.childNodes.length;
        let maxHeight = childHeight * childCount;
        let toHeight = container.scrollTop;
        let current = 0;
        dataList.push({
          parentHeight,
          scrollHeight,
          childHeight,
          childCount,
          maxHeight,
          toHeight,
          current,
          timer: null,
          timerMouseWheel: null,
        });
        function scrollCore() {
          {
            if (scrollHeight > parentHeight) {
              dataList[i].timer = setInterval(() => {
                let scrollStep = 1; // 每帧滚动的步长,可以适当调整
                if (container.scrollTop + parentHeight + 5 >= scrollHeight) {
                  // 如果滚动到底部,则将滚动位置重置为0
                  container.scrollTop = 0;
                  dataList[i].toHeight = 0;
                  dataList[i].current = 0;
                } else {
                  if (container.scrollTop < dataList[i].toHeight + dataList[i].childHeight) {
                    // 如果尚未滚动到目标位置,则逐帧更新滚动位置
                    container.scrollTop += scrollStep;
                  } else {
                    // 已滚动到目标位置,更新当前子项索引和子项高度
                    dataList[i].current = (dataList[i].current + 1) % dataList[i].childCount;
                    dataList[i].childHeight = container.childNodes[dataList[i].current].offsetHeight;
                    dataList[i].toHeight = container.scrollTop;
                  }
                }
              }, 2000 / 60); // 设置每秒更新60次,可根据需求调整
            }
          }
        }
        scrollCore()
      }
    },
  },
  mounted() {},
};
</script>

注:该方法在自动滚动到底部后会返回到顶部,循环滚动需要更改逻辑,在下方有循环的方法。

二、如何暂时关闭自动滚动

当我们想自己通过鼠标滚轮滚动该列表时,使该列表的自动滚动暂停,我们可以添加了一个名为mousewheel的事件监听器,以便在鼠标滚轮滚动时执行以下操作:

  • 清除之前的定时器dataList[i].timerdataList[i].timerMouseWheel
  • 更新dataList[i].toHeight为当前滚动位置,并将滚动位置设置为相同的值。
  • 设置一个新的定时器dataList[i].timerMouseWheel,在一段时间后重新调用scrollCore函数,以恢复自动滚动效果。
 container.addEventListener("mousewheel", () => {
          this.$nextTick(() => {
            clearInterval(dataList[i].timer);
            clearInterval(dataList[i].timerMouseWheel);
            dataList[i].toHeight = container.scrollTop;
            container.scrollTop = container.scrollTop;
            dataList[i].timerMouseWheel = setTimeout(() => {
              scrollCore()
            }, 3000)
          });
        });

三、如何彻底关闭自动滚动

在上面的方法中会一直无限的滚动下去,那么我们如果想停下具体看某一项要把自动滚动关闭掉呢,我们可以通过将关闭方法写在container的某个事件中,并将该事件派发给container来实现

// 监听关闭自动滚动的事件
container.addEventListener("closeScroll", () => {
          this.$nextTick(() => {
            clearInterval(dataList[i].timer);
            clearInterval(dataList[i].timerMouseWheel);
            toHeight = container.scrollTop;
            container.scrollTop = container.scrollTop;
          });
        });
// 完整代码
// 关闭列表自动滚动
    closeListScroll(container) {
      // 创建一个新的 自定义 事件
      const closeScroll = new Event("closeScroll");
      container.dispatchEvent(closeScroll)
    },
// 列表自动滚动
    scrollFn() {
      let dataList = [];
      for (let i = 0; i < 1; i++) {
        let container = this.$refs["scroll" + i];
        let parentHeight = container.offsetHeight || 0;
        let scrollHeight = container.scrollHeight;
        let childHeight = container.firstChild.offsetHeight;
        let childCount = container.childNodes.length;
        let maxHeight = childHeight * childCount;
        let toHeight = container.scrollTop;
        let current = 0;
        dataList.push({
          parentHeight,
          scrollHeight,
          childHeight,
          childCount,
          maxHeight,
          toHeight,
          current,
          timer: null,
          timerMouseWheel: null,
        });
        function scrollCore() {
          {
            if (scrollHeight > parentHeight) {
              dataList[i].timer = setInterval(() => {
                let scrollStep = 1; // 每帧滚动的步长,可以适当调整
                if (container.scrollTop + parentHeight + 5 >= scrollHeight) {
                  // 如果滚动到底部,则将滚动位置重置为0
                  container.scrollTop = 0;
                  dataList[i].toHeight = 0;
                  dataList[i].current = 0;
                } else {
                  if (container.scrollTop < dataList[i].toHeight + dataList[i].childHeight) {
                    // 如果尚未滚动到目标位置,则逐帧更新滚动位置
                    container.scrollTop += scrollStep;
                  } else {
                    // 已滚动到目标位置,更新当前子项索引和子项高度
                    dataList[i].current = (dataList[i].current + 1) % dataList[i].childCount;
                    dataList[i].childHeight = container.childNodes[dataList[i].current].offsetHeight;
                    dataList[i].toHeight = container.scrollTop;
                  }
                }
              }, 2000 / 60); // 设置每秒更新60次,可根据需求调整
            }
          }
        }
        scrollCore()
        container.addEventListener("mousewheel", () => {
          this.$nextTick(() => {
            clearInterval(dataList[i].timer);
            clearInterval(dataList[i].timerMouseWheel);
            dataList[i].toHeight = container.scrollTop;
            container.scrollTop = container.scrollTop;
            dataList[i].timerMouseWheel = setTimeout(() => {
              scrollCore()
            }, 3000)
          });
        });
        container.addEventListener("closeScroll", () => {
          this.$nextTick(() => {
            clearInterval(dataList[i].timer);
            clearInterval(dataList[i].timerMouseWheel);
            toHeight = container.scrollTop;
            container.scrollTop = container.scrollTop;
          });
        });
      }
    },

通过如上代码 我们就可以通过调用closeListScroll()方法来关闭列表自动滚动,如我们想要关闭ref=scroll0列表的自动滚动

// 示例 关闭ref=scroll0列表的自动滚动
// 某个方法中
clickSomeBtn(){
    ... //其他逻辑
    this.closeListScroll(this.$refs["scroll0"])
}

四、如何使自动滚动无限循环,使其头尾相连

思路:将一份数据复制为两份,在滚动到第二份与第一份重合的时候 立刻将滚动高度归位,这样从视觉效果上来看,就是无限滚动的效果 要实现这个效果,首先是我们需要将一份数据变为两份,最为简单的实现思路为直接将数据变为两份

<li class="gaojing_info_list" v-for="(item, index) in [...scrollInfoList,...scrollInfoList]" :key="index">

但是这样的话,我们需要对所有的列表都进行更改,容易遗漏,不符合封装思路
于是我就想着通过DOM方法直接在封装函数中进行操作,实现思路为

  • 使用DOM方法获取container的所有子元素,并将它们存储在名为children的变量中。
  • 创建一个文档片段(Document Fragment)并将子元素逐个克隆并添加到文档片段中。
  • 一次性将文档片段添加回container中,以提高性能。 当我们实现了克隆两份数据后,通过对container.scrollTop >= scrollHeight / 2的判断,来得到我们已经来到了第二页与初始位置重复的位置,在这个时候将滚动位置重置,在视觉上就会实现首尾相连无限滚动的效果
// 列表自动循环滚动
scrollFn() {
  let dataList = [];
  for (let i = 0; i < 1; i++) {
    let container = this.$refs["scroll" + i];
    console.log(container);
    // 使用 DOM 方法获取所有子元素
    let children = container.children;
    // 创建一个文档片段
    let fragment = document.createDocumentFragment();
    // 将子元素逐个重新插入到容器中
    for (let ind = 0; ind < children.length; ind++) {
      const child = children[ind].cloneNode(true);
      console.log(child, "child");
      fragment.appendChild(child);
    }
    // 一次性将文档片段添加回容器中
    this.$refs["scroll" + i].appendChild(fragment);
    let parentHeight = container.offsetHeight || 0;
    let scrollHeight = container.scrollHeight;
    let childHeight = container.firstChild.offsetHeight;
    let childCount = container.childNodes.length;
    let maxHeight = childHeight * childCount;
    let toHeight = container.scrollTop;
    let current = 0;
    dataList.push({
      parentHeight,
      scrollHeight,
      childHeight,
      childCount,
      maxHeight,
      toHeight,
      current,
      timer: null,
    });
    function scrollCore() {
      if (scrollHeight > parentHeight) {
        dataList[i].timer = setInterval(() => {
          let scrollStep = 1; // 每帧滚动的步长,可以适当调整
          if (container.scrollTop >= scrollHeight / 2) {
            // 滚动到与第一行重复的位置后 重置
            container.scrollTop = 0;
            dataList[i].toHeight = 0;
            dataList[i].current = 0;
          } else {
            if (
              container.scrollTop <
              dataList[i].toHeight + dataList[i].childHeight
            ) {
              // 如果尚未滚动到目标位置,则逐帧更新滚动位置
              container.scrollTop += scrollStep;
            } else {
              // 已滚动到目标位置,更新当前子项索引和子项高度
              dataList[i].current =
                (dataList[i].current + 1) % dataList[i].childCount;
              dataList[i].childHeight =
                container.childNodes[dataList[i].current].offsetHeight;
              dataList[i].toHeight = container.scrollTop;
            }
          }
        }, 2000 / 60); // 设置每秒更新60次,可根据需求调整
      }
    }
    scrollCore();
    container.addEventListener("mousewheel", () => {
      this.$nextTick(() => {
        clearInterval(dataList[i].timer);
        clearInterval(dataList[i].timerMouseWheel);
        dataList[i].toHeight = container.scrollTop;
        container.scrollTop = container.scrollTop;
        dataList[i].timerMouseWheel = setTimeout(() => {
          scrollCore();
        }, 3000);
      });
    });
     container.addEventListener("closeScroll", () => {
          this.$nextTick(() => {
            clearInterval(dataList[i].timer);
            clearInterval(dataList[i].timerMouseWheel);
            toHeight = container.scrollTop;
            container.scrollTop = container.scrollTop;
          });
        });
  }
}

以上就是vue封装实现自动循环滚动的列表的详细内容,更多关于vue循环滚动列表的资料请关注脚本之家其它相关文章!

相关文章

  • vue3 使用provide inject父子组件传值失败且子组件不响应

    vue3 使用provide inject父子组件传值失败且子组件不响应

    这篇文章主要介绍了vue3使用provide inject父子组件传值传不过去且传递后子组件不具备响应性问题解决方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • vue3+vite:src使用require动态导入图片报错的最新解决方法

    vue3+vite:src使用require动态导入图片报错的最新解决方法

    这篇文章主要介绍了vue3+vite:src使用require动态导入图片报错和解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Vue3中v-if和v-for优先级实例详解

    Vue3中v-if和v-for优先级实例详解

    Vue.js中使用最多的两个指令就是v-if和v-for,下面这篇文章主要给大家介绍了关于Vue3中v-if和v-for优先级的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • 基于Vue + ElementUI实现可编辑表格及校验

    基于Vue + ElementUI实现可编辑表格及校验

    这篇文章主要给大家介绍了基于Vue + ElementUI 实现可编辑表格及校验,文中有详细的代码讲解和实现思路,讲解的非常详细,有需要的朋友可以参考下
    2023-08-08
  • Vue3中watch与watchEffect使用方法详解

    Vue3中watch与watchEffect使用方法详解

    在Vue中,watch和watchEffect都是用于观察和响应数据变化的工具,但它们在使用方式和功能上有一些显著的区别,这篇文章主要介绍了Vue3中watch与watchEffect使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-09-09
  • Vue Router应用方法详解

    Vue Router应用方法详解

    在看这篇文章的几点要求:需要你先知道Vue-Router是个什么东西,用来解决什么问题,以及它的基本使用。如果你还不懂的话,建议上官网了解下Vue-Router的基本使用后再回来看这篇文章
    2022-09-09
  • Vue2 elementui2 中 el-switch 实现先判断改变状态

    Vue2 elementui2 中 el-switch 实现先判断改变状态

    本文给大家介绍Vue2 elementui2中el-switch实现先判断改变状态的相关知识,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2026-03-03
  • Vue中非父子组件通信的方法小结

    Vue中非父子组件通信的方法小结

    在Vue.js中,组件间的通信是构建复杂应用的关键,但当涉及到非父子关系的组件通信时,传统的做法就显得力不从心了,本文将深入探讨几种有效的非父子组件通信方法,并通过具体的代码示例来帮助读者理解和应用这些技术,需要的朋友可以参考下
    2024-09-09
  • vue3的api解读之ref和reactive示例详解

    vue3的api解读之ref和reactive示例详解

    这篇文章主要介绍了vue3的api解读之ref和reactive详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • 利用Electron简单撸一个Markdown编辑器的方法

    利用Electron简单撸一个Markdown编辑器的方法

    这篇文章主要介绍了利用Electron简单撸一个Markdown编辑器的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06

最新评论