vue封装实现自动循环滚动的列表
作者: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].timer
和dataList[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循环滚动列表的资料请关注脚本之家其它相关文章!