原创 赛博丁真Damon 2025-04-22 08:32 重庆
点击关注公众号,“技术干货” 及时达!
关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding
背景及需求
背景: 在大屏项目中,经常会存在列表循环滚动的动画。 当存在很多个列表都需要动画的时候, 重复代码既不够优雅,也不便于维护(当甲方觉得速度快慢调整或其他调整时候,需要重复修改)。
需求:
代码效果展示
列表滚动动画vue指令网址:
https://code.juejin.cn/pen/7400691681794162728
详解
requestAnimationFrame
进行列表动画滚动动画,并通过回调接口的timeStamp
时间戳来控制动画进行的速度。mounted
生命周期定义变量isUsing
来辨别当前用户是否正在与元素交互中(点击,鼠标滚动, 移入等,根据业务需求), 为元素增添监听鼠标点击、移入移出事件来控制交互期间的动画状态.一些思考
为什么使用requestAnimationFrame
而不是使用setTimeout
或setInterval
实现? 在数据可视化
需要定制动画的情况下,requestAnimationFrame
的稳定性、交互性、流畅度和易用性都是优优于其他二者的,是与浏览器刷新都挂钩的
在当前浏览器的支持度也十分良好
当然在极限的情况下,也需要额外适配,在下面代码中我也有预留当浏览器不支持时候可以使用setTimeout
或setInterval
实现。
核心代码
vue 指令实现
{
arr: {},
mounted(el, binding = { value: 200 }, vnode, prevVnode) {
const gap = 1000 / 45; // 帧数差距, 浏览器大概1s 60帧, 数字 > 60 效果应该一致,数字越小越慢
if (window.requestAnimationFrame) {
let isUsing = false; // 是否介入操作;介入操作时暂停动画;
// 鼠标移出时,继续动画
el.addEventListener('mouseleave', () => {
isUsing && scrollAnimation(); // 如果动画已暂停,重置动画
isUsing = false;
}, { passive: true } )
// 鼠标滚动时,继续动画
el.addEventListener('wheel', () => {
isUsing = true;
}, { passive: true } )
// 鼠标点击时, 暂停动画
el.addEventListener('click', () => {
isUsing = true;
}, { passive: true } )
// 动画方法
const scrollAnimation = () => {
if (window.requestAnimationFrame) {
/**
* @Author: Damon Liu
* @Date: 2024-04-29 10:28:37
* @LastEditors: Damon Liu
* @LastEditTime:
* @Description:
* @param {*} timeStamp 当前时间戳
* @param {*} preTimeStamp 上一帧时间戳
* @param {*} diff 累计的时间差
*/
let animationFun = (timeStamp, preTimeStamp = 0, diff = 0) => {
if (isUsing) {
return
}
let currentDiff = preTimeStamp === 0 ? 0 : timeStamp - preTimeStamp; // 当前时间差
let n_diff = currentDiff + diff; // 总时间差
// 当总时间差比小于帧数差距时,不执行动画,申请下一帧执行
if(n_diff < gap) {
window.requestAnimationFrame((_timeStamp) => animationFun(_timeStamp, timeStamp, n_diff))
return ;
}
let scrollTop = el.scrollTop; // 滚动条顶部
let clientHeight = el.clientHeight; // 内容高度
let scrollHeight = el.scrollHeight; // 滚动内容高度
// 当没有滚动至底部时
if (scrollTop + clientHeight < scrollHeight) {
el.scrollTop = scrollTop + 1;
window.requestAnimationFrame((_timeStamp) => animationFun(_timeStamp, timeStamp, 0));
}
// 滚动至底部重置动画
else {
el.scrollTop = 0;
scrollAnimation();
}
}
// 开始动画
window.requestAnimationFrame(animationFun);
}
}
scrollAnimation()
}
else {
}
},
unmounted(el, binding, vnode, prevVnode) {
}
}
额外拓展
存在额外需求, 如需要手动去控制列表是否滚动时候,可通过指令传入额外变量去进行控制。
列表滚动动画也可以更改为其他动画,如颜色的变化以及形状,位移等。总体的思路一致。