起因
vue3大屏开发过程中,列表长度不定,需要做在滚动显示的设计,于是乎在npmjs上找到了下载量超高的无缝滚动的插件,集成简单快捷,体验也很好,不得不说是一个非常优秀的插件,但其有一个致命的缺陷,就是性能问题,当单个基于element-ui编写的组件使用该插件,cpu增加30%左右,当超过4个组件使用,cpu会飙升至120%左右,后期稳定在107~154%之间(chrome使用shift+esc键可打开监控,查看资源占用情况),此刻配置差一点的机器是无法正常工作的,无奈之下只能选择自己造轮子了。
演示地址
项目中使用
目前该组件已经发布至npmjs仓库,进行了多次补丁升级,欢迎大家使用
安装
npm install --save tank-vue3-seamless-scroll
导入
import TankSeamlessScroll from "tank-vue3-seamless-scroll"
使用组件
<div style="height:300px;">
<tank-seamless-scroll :step-length="25" :debug="true" :reverse="false">
<div class="demo">
<div v-for="i in 2" :key="i">测试{{ i }}</div>
</div>
</tank-seamless-scroll>
</div>
git 仓库
效果展示
造轮子的过程
渲染问题
首先我们要考虑基于fps帧渲染的,那么我们必定会优先考虑 requestAnimationFrame 对象,为快速解决问题,我们使用了d3-timer 插件,默认帧率限制在了(1000/32)ms,也就是32帧。
性能
偏移量更新采用了js设置 css3 3d 模式,保证了性能可利用
ref_warp.value.style.setProperty("transform", `translate3d(0px ,${translateY}px,0px)`)
显示分析
有限复制
复制的目的是为解决连续滚动时,当超出当前容器,继续可视连续的滚动画面,这就预示着我们至少需要×3容器容纳倍数的内容,才能实现无缝滚动,为了提高性能,最后决定最多把这个数字限定为3,考虑到内容高度有可能小于或大于容器高度,所以引出了以下公式:
- 复制总量 = 向上四舍五入(容器高度/ 内容高度) ×3 PS:
- 越小的内容复制数量越多,越大的内容填充数量越少,目的只是为了避免视觉白屏的闪烁
- 无限复制会降低开发难度,但是vue组件无限复制性能问题无法解决,dom复制,无法继承源内容的事件熟悉
限定位Y
当画面滚动到第三页时,若继续滚动,则画面会出现空白内容,因为没有第四页了,所以我们要把第二页的最后一个内容底坐标作为限定位Y,可理解为最终一直循环播放第一页2th内容块到第三页倒数第二个内容块之间内容,但用户是无感知的。
位置计算公式
如果Y轴偏移量大于限定位Y 则需要重新恢复到首个内容块 + 取偏移余Y的位置,进行循环滚动 偏移Y = 偏移Y<限定位Y?符号*(绝对值(偏移Y%内容高度)+内容高度):偏移Y
补充
- 插件增加了debug模式,开启后会实时显示帧率、偏移量、复制总量
- 插件增加了反向滚动模式,需要开启 reverse 模式
- 插件增加了滚动步长速度控制,需要配置 step-length ,该属性值 代表:Y轴偏移量 (像素/秒)