在大屏或者某些不常使用鼠标交互的页面,数据在定时刷新,如果有个列表数据过多,需要数据自己滚动展示。这里写个通用指令,需要的地方加上即可,轻量。
功能
若容器有滚动条则开启自动滚动,鼠标移入时停止,鼠标移除时继续滚动,可设置自动滚动的动画延迟多久开始启动。目前只支持y方向的,x方向自行扩展,懒得写,加起来也简单。
代码
/**
* author: yf
* date: 20241219
* 列表自动滚动 - 目前只支持 y方向,暂时没有x方向的需求
* 功能:
* 若容器有滚动条则开启自动滚动,鼠标移入时停止,鼠标移除时继续滚动
* 使用方式:
* 方式一:在滚动节点上使用默认配置
v-auto-scroll
* 方式二:完整配置
v-auto-scroll = {
targetSelector: '.el-table__body-wrapper', // 当前指令挂载节点内部的滚动盒子,使用 el.querySelector(targetSelector) 查找,节点不存在则使用 el 节点
delayTime: 1000, // 自动滚动开启的延迟时间,单位 ms
speed: 2, // 自动滚动速度,值越小滚动速度越快,最小速度为 1
interval: 1 // 每次自动滚动时移动的距离,单位px - 注意:必须是正整数
}
*/
Vue.directive('auto-scroll', {
inserted: function (el, binding) {
// console.log(el, binding, vnode);
// 获取配置参数
let {
targetSelector = '',
delayTime = 1000, // 自动滚动开启的延迟时间,单位 ms
speed = 4.5, // 自动滚动速度,值越小滚动速度越快,最小速度为 1
interval = 1 // 每次自动滚动时移动的距离,单位px - 注意:必须是正整数
} = binding.value || {};
// 正整数处理
interval = Math.abs(Math.ceil(interval));
el._customData = {}; // 需要移除的
let disabledScroll = false; // 禁止滚动
let delayTimeSum = 0; // 累计时间,用于判断是否达到延迟时间
// 滚动元素
let scrollTarget = targetSelector ? el.querySelector(targetSelector) : '';
scrollTarget = scrollTarget || el;
if (!scrollTarget) return;
let touchBottom = scrollTarget.scrollHeight - scrollTarget.scrollTop <= scrollTarget.clientHeight // 是否触底
// 事件处理
let customEvent = {
mouseover: function () {
disabledScroll = true;
},
mouseout: function () {
disabledScroll = false;
delayTimeSum = 0; // 清空
}
};
// 移入时关闭自动滚动
el.addEventListener('mouseover', customEvent.mouseover, false);
// 移出时开启自动滚动
el.addEventListener('mouseout', customEvent.mouseout, false);
// 自动滚动
let preTime = Date.now();
let curTime = null;
let diffTime = Math.max(...[1000 / 60, (1000 / 60) * speed]); // 动画间隔
let mutiTime = 1 // 滚动时间倍数,滚动距离过短时,延长动画时间 - 经测这样效果最好
let autoScroll = () => {
if (scrollTarget.scrollHeight <= scrollTarget.clientHeight) return; // 无滚动条,不具备滚动条件
if (disabledScroll) return;
// 滚动距离过短,滚动时间延长
if (scrollTarget.scrollHeight <= 1.8 * scrollTarget.clientHeight) {
mutiTime = 2.5
} else {
mutiTime = 1
}
// 判断滚动条是否到底部
if (scrollTarget.scrollHeight - scrollTarget.scrollTop <= scrollTarget.clientHeight) {
// 触底后延迟 delayTime 再从头开始动画
if (!touchBottom) {
touchBottom = true
delayTimeSum = 0; // 延迟再从头开始滚动
} else {
touchBottom = false
scrollTarget.scrollTop = 0;
}
} else {
scrollTarget.scrollTop += interval;
}
};
(function animloop() {
curTime = Date.now();
if (curTime - preTime > diffTime * mutiTime) {
// 在延迟时间内不执行动画
if (delayTimeSum >= delayTime) {
autoScroll();
} else {
delayTimeSum += curTime - preTime;
}
preTime = curTime;
}
el._customData.raId = requestAnimationFrame(animloop);
})();
el._customData.customEvent = customEvent;
},
/* eslint-disable no-unused-vars */
unbind(el) {
/* eslint-enable no-unused-vars */
// 解绑
let _customData = el._customData;
if (!el || !_customData) return;
cancelAnimationFrame(_customData.raId);
el.removeEventListener('mouseover', _customData.customEvent.mouseover);
el.removeEventListener('mouseout', _customData.customEvent.mouseout);
}
});
效果如下
方式一:直接添加到滚动盒子上
<ul class="test-box" v-auto-scroll>
<li v-for="item in 20" :key="item">{{item}}</li>
</ul>
方式二: element-ui 的 el-table
v-auto-scroll="{
targetSelector:'.el-table__body-wrapper'
}
若对你有帮助,请点个赞吧,若能打赏不胜感激,谢谢支持!
本文地址:https://www.jianshu.com/p/e43ceee4aeca?v=1734601770680,转载请注明出处,谢谢。