vue封裝實(shí)現(xiàn)自動(dòng)循環(huán)滾動(dòng)的列表
前言
在做數(shù)據(jù)大屏開(kāi)發(fā)的過(guò)程中,經(jīng)常出現(xiàn)需要對(duì)列表進(jìn)行自動(dòng)滾動(dòng)的需求,為了個(gè)性化的實(shí)現(xiàn)各種需求,就封裝了一個(gè)函數(shù)方法

解決方案
- 生成一個(gè)父元素,并給其固定的高度,通過(guò)$refs獲取并賦值給
container變量 - 獲取一些關(guān)于
container和其子元素的信息,如父容器高度(parentHeight)、滾動(dòng)高度(scrollHeight)、第一個(gè)子元素的高度(childHeight)、子元素?cái)?shù)量(childCount)、最大高度(maxHeight)、當(dāng)前滾動(dòng)位置(toHeight)和當(dāng)前子元素索引(current),并初始化一個(gè)名為timer的計(jì)時(shí)器。 - 定義一個(gè)名為
scrollCore的函數(shù),該函數(shù)用于實(shí)現(xiàn)滾動(dòng)效果。 - 在
scrollCore函數(shù)中檢查如果scrollHeight大于parentHeight,則創(chuàng)建一個(gè)定時(shí)器,以便每隔一段時(shí)間執(zhí)行一次滾動(dòng)操作。 - 在定時(shí)器中,
scrollCore函數(shù)中逐漸增加容器的scrollTop屬性,從而實(shí)現(xiàn)滾動(dòng)效果。
一、勻速自動(dòng)滾動(dòng),并實(shí)現(xiàn)方法可對(duì)多個(gè)列表復(fù)用
思路:通過(guò)對(duì)ref的命名,來(lái)實(shí)現(xiàn)在方法中使用for循環(huán)來(lái)對(duì)多個(gè)列表生效
<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: {
// 列表自動(dòng)滾動(dòng)
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; // 每幀滾動(dòng)的步長(zhǎng),可以適當(dāng)調(diào)整
if (container.scrollTop + parentHeight + 5 >= scrollHeight) {
// 如果滾動(dòng)到底部,則將滾動(dòng)位置重置為0
container.scrollTop = 0;
dataList[i].toHeight = 0;
dataList[i].current = 0;
} else {
if (container.scrollTop < dataList[i].toHeight + dataList[i].childHeight) {
// 如果尚未滾動(dòng)到目標(biāo)位置,則逐幀更新滾動(dòng)位置
container.scrollTop += scrollStep;
} else {
// 已滾動(dòng)到目標(biāo)位置,更新當(dāng)前子項(xiàng)索引和子項(xiàng)高度
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); // 設(shè)置每秒更新60次,可根據(jù)需求調(diào)整
}
}
}
scrollCore()
}
},
},
mounted() {},
};
</script>注:該方法在自動(dòng)滾動(dòng)到底部后會(huì)返回到頂部,循環(huán)滾動(dòng)需要更改邏輯,在下方有循環(huán)的方法。
二、如何暫時(shí)關(guān)閉自動(dòng)滾動(dòng)
當(dāng)我們想自己通過(guò)鼠標(biāo)滾輪滾動(dòng)該列表時(shí),使該列表的自動(dòng)滾動(dòng)暫停,我們可以添加了一個(gè)名為mousewheel的事件監(jiān)聽(tīng)器,以便在鼠標(biāo)滾輪滾動(dòng)時(shí)執(zhí)行以下操作:
- 清除之前的定時(shí)器
dataList[i].timer和dataList[i].timerMouseWheel。 - 更新
dataList[i].toHeight為當(dāng)前滾動(dòng)位置,并將滾動(dòng)位置設(shè)置為相同的值。 - 設(shè)置一個(gè)新的定時(shí)器
dataList[i].timerMouseWheel,在一段時(shí)間后重新調(diào)用scrollCore函數(shù),以恢復(fù)自動(dòng)滾動(dòng)效果。
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)
});
});三、如何徹底關(guān)閉自動(dòng)滾動(dòng)
在上面的方法中會(huì)一直無(wú)限的滾動(dòng)下去,那么我們?nèi)绻胪O戮唧w看某一項(xiàng)要把自動(dòng)滾動(dòng)關(guān)閉掉呢,我們可以通過(guò)將關(guān)閉方法寫(xiě)在container的某個(gè)事件中,并將該事件派發(fā)給container來(lái)實(shí)現(xiàn)
// 監(jiān)聽(tīng)關(guān)閉自動(dòng)滾動(dòng)的事件
container.addEventListener("closeScroll", () => {
this.$nextTick(() => {
clearInterval(dataList[i].timer);
clearInterval(dataList[i].timerMouseWheel);
toHeight = container.scrollTop;
container.scrollTop = container.scrollTop;
});
});// 完整代碼
// 關(guān)閉列表自動(dòng)滾動(dòng)
closeListScroll(container) {
// 創(chuàng)建一個(gè)新的 自定義 事件
const closeScroll = new Event("closeScroll");
container.dispatchEvent(closeScroll)
},
// 列表自動(dòng)滾動(dòng)
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; // 每幀滾動(dòng)的步長(zhǎng),可以適當(dāng)調(diào)整
if (container.scrollTop + parentHeight + 5 >= scrollHeight) {
// 如果滾動(dòng)到底部,則將滾動(dòng)位置重置為0
container.scrollTop = 0;
dataList[i].toHeight = 0;
dataList[i].current = 0;
} else {
if (container.scrollTop < dataList[i].toHeight + dataList[i].childHeight) {
// 如果尚未滾動(dòng)到目標(biāo)位置,則逐幀更新滾動(dòng)位置
container.scrollTop += scrollStep;
} else {
// 已滾動(dòng)到目標(biāo)位置,更新當(dāng)前子項(xiàng)索引和子項(xiàng)高度
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); // 設(shè)置每秒更新60次,可根據(jù)需求調(diào)整
}
}
}
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;
});
});
}
},通過(guò)如上代碼 我們就可以通過(guò)調(diào)用closeListScroll()方法來(lái)關(guān)閉列表自動(dòng)滾動(dòng),如我們想要關(guān)閉ref=scroll0列表的自動(dòng)滾動(dòng)
// 示例 關(guān)閉ref=scroll0列表的自動(dòng)滾動(dòng)
// 某個(gè)方法中
clickSomeBtn(){
... //其他邏輯
this.closeListScroll(this.$refs["scroll0"])
}四、如何使自動(dòng)滾動(dòng)無(wú)限循環(huán),使其頭尾相連
思路:將一份數(shù)據(jù)復(fù)制為兩份,在滾動(dòng)到第二份與第一份重合的時(shí)候 立刻將滾動(dòng)高度歸位,這樣從視覺(jué)效果上來(lái)看,就是無(wú)限滾動(dòng)的效果 要實(shí)現(xiàn)這個(gè)效果,首先是我們需要將一份數(shù)據(jù)變?yōu)閮煞?,最為?jiǎn)單的實(shí)現(xiàn)思路為直接將數(shù)據(jù)變?yōu)閮煞?/p>
<li class="gaojing_info_list" v-for="(item, index) in [...scrollInfoList,...scrollInfoList]" :key="index">
但是這樣的話,我們需要對(duì)所有的列表都進(jìn)行更改,容易遺漏,不符合封裝思路
于是我就想著通過(guò)DOM方法直接在封裝函數(shù)中進(jìn)行操作,實(shí)現(xiàn)思路為
- 使用DOM方法獲取
container的所有子元素,并將它們存儲(chǔ)在名為children的變量中。 - 創(chuàng)建一個(gè)文檔片段(Document Fragment)并將子元素逐個(gè)克隆并添加到文檔片段中。
- 一次性將文檔片段添加回
container中,以提高性能。 當(dāng)我們實(shí)現(xiàn)了克隆兩份數(shù)據(jù)后,通過(guò)對(duì)container.scrollTop >= scrollHeight / 2的判斷,來(lái)得到我們已經(jīng)來(lái)到了第二頁(yè)與初始位置重復(fù)的位置,在這個(gè)時(shí)候?qū)L動(dòng)位置重置,在視覺(jué)上就會(huì)實(shí)現(xiàn)首尾相連無(wú)限滾動(dòng)的效果
// 列表自動(dòng)循環(huán)滾動(dòng)
scrollFn() {
let dataList = [];
for (let i = 0; i < 1; i++) {
let container = this.$refs["scroll" + i];
console.log(container);
// 使用 DOM 方法獲取所有子元素
let children = container.children;
// 創(chuàng)建一個(gè)文檔片段
let fragment = document.createDocumentFragment();
// 將子元素逐個(gè)重新插入到容器中
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; // 每幀滾動(dòng)的步長(zhǎng),可以適當(dāng)調(diào)整
if (container.scrollTop >= scrollHeight / 2) {
// 滾動(dòng)到與第一行重復(fù)的位置后 重置
container.scrollTop = 0;
dataList[i].toHeight = 0;
dataList[i].current = 0;
} else {
if (
container.scrollTop <
dataList[i].toHeight + dataList[i].childHeight
) {
// 如果尚未滾動(dòng)到目標(biāo)位置,則逐幀更新滾動(dòng)位置
container.scrollTop += scrollStep;
} else {
// 已滾動(dòng)到目標(biāo)位置,更新當(dāng)前子項(xiàng)索引和子項(xiàng)高度
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); // 設(shè)置每秒更新60次,可根據(jù)需求調(diào)整
}
}
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封裝實(shí)現(xiàn)自動(dòng)循環(huán)滾動(dòng)的列表的詳細(xì)內(nèi)容,更多關(guān)于vue循環(huán)滾動(dòng)列表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vue3?使用provide?inject父子組件傳值失敗且子組件不響應(yīng)
這篇文章主要介紹了vue3使用provide?inject父子組件傳值傳不過(guò)去且傳遞后子組件不具備響應(yīng)性問(wèn)題解決方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
vue3+vite:src使用require動(dòng)態(tài)導(dǎo)入圖片報(bào)錯(cuò)的最新解決方法
這篇文章主要介紹了vue3+vite:src使用require動(dòng)態(tài)導(dǎo)入圖片報(bào)錯(cuò)和解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
Vue3中v-if和v-for優(yōu)先級(jí)實(shí)例詳解
Vue.js中使用最多的兩個(gè)指令就是v-if和v-for,下面這篇文章主要給大家介紹了關(guān)于Vue3中v-if和v-for優(yōu)先級(jí)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
基于Vue?+?ElementUI實(shí)現(xiàn)可編輯表格及校驗(yàn)
這篇文章主要給大家介紹了基于Vue?+?ElementUI?實(shí)現(xiàn)可編輯表格及校驗(yàn),文中有詳細(xì)的代碼講解和實(shí)現(xiàn)思路,講解的非常詳細(xì),有需要的朋友可以參考下2023-08-08
Vue2 elementui2 中 el-switch 實(shí)現(xiàn)先判斷改變狀態(tài)
本文給大家介紹Vue2 elementui2中el-switch實(shí)現(xiàn)先判斷改變狀態(tài)的相關(guān)知識(shí),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2026-03-03
利用Electron簡(jiǎn)單擼一個(gè)Markdown編輯器的方法
這篇文章主要介紹了利用Electron簡(jiǎn)單擼一個(gè)Markdown編輯器的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-06-06

