数据可视化大屏列表循环滚动动画Vue指令封装(requestAnimationFrame)
关注更多AI编程资讯请去AI Coding专区:https://juejin.cn/aicoding
背景及需求
背景: 在大屏项目中,经常会存在列表循环滚动的动画。 当存在很多个列表都需要动画的时候, 重复代码既不够优雅,也不便于维护(当甲方觉得速度快慢调整或其他调整时候,需要重复修改)。
需求:
列表上下滚动动画循环播放 当鼠标点击列表时候,滚动暂停 当鼠标移出列表元素时候,重新触发滚动 可调整列表滚动的速度(甲方屁事多的情况下)
代码效果展示
列表滚动动画vue指令网址:
https://code.juejin.cn/pen/7400691681794162728
详解
通过 requestAnimationFrame进行列表动画滚动动画,并通过回调接口的timeStamp时间戳来控制动画进行的速度。通过vue指令进行封装,并且在指令 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) {}}
额外拓展
存在额外需求, 如需要手动去控制列表是否滚动时候,可通过指令传入额外变量去进行控制。
列表滚动动画也可以更改为其他动画,如颜色的变化以及形状,位移等。总体的思路一致。