背景
在一个数据看板项目中,需要实现一个像 LED 屏幕一样,无限无缝轮播学生数据的组件,效果如下:
“这还不简单,直接用 Swiper 啊!”
然而实在不想为了这一小功能而引入一个 4M 大小的 Npm 包,于是决定自己动手实现
思路
直接把所有数据放在 Dom 中,之后用 Css Animation
控制它们持续向上,显然是不可能的,咱们的数据可能有成千上万条
所以肯定需要 JS 的介入,来在某些时机动态地删改数据
但也不能直接定时地对数据进行 shift + push 操作,否则数据元素的位置会瞬间偏移到上方
我想到的是,把数据分为上下两块 A 和 B,让其自然向上移动,当滚动到 A、B 的交界处碰到容器上边缘(即 A 完全看不到)时,将 A -> B,B -> C,并重置动画,如下 Demo 所示:
如此便实现了旧数据的删除与新数据的增加,并且视窗内的数据元素从肉眼看上去是无缝衔接的
实现方式1
思路有了,接下来就是代码的实现方式
首先我想当然地,用 CSS Animation
让容器内的数据的 top 值不断减小(负数),同时 JS 利用 setInterval
在恰好的时间节点动态地更替数据
然而重点就在于,这个“恰好的时间节点”是无法把控的,首先 JS 的定时器本就不完全精确,另外 CSS 与 JS 的定时器更不会如我们所愿地完全一致
实现方式2
既然 JS 和 CSS 不愿顺从彼此,那就只能二选一了
于是我把动画也交给 JS 来执行,让其在 window.requestAnimationFrame
中按照一定频率增加对应元素的 top 值,并在其值增加到一定节点时操作数据
如此是能呈现出预期效果,但也产生了新的问题:
- top 值改变的频率与单位值如果小了,视觉上会出现明显的跳帧(可用
transitions
来修补过渡) - 由于是 JS 通过 DOM 操作实现的动画,性能成本一下高了起来,在低端机器上将卡得惨不忍睹...
最终方式
术业有专攻,看来动画还是得交给 CSS 来实现,那么问题就回到了如何保持 CSS 与 JS 改变时机的一致性
定时器已经行不通了,所以 JS 需要寻找新的方式来感知数据元素们所在的位置
于是我把目光转向了一个较冷门的 API:IntersectionObserver
(教程在此)
在对一个 Dom 进行 observe
后,便能及时得知其可见状态的改变,因此我们可以很方便地在 A 数据由可见 -> 不可见时收到通知,进行数据更替操作
而因为交叉观察器只会在元素的可见状态改变时触发 callback,因此性能问题也无需担心
安全边际
由于 IntersectionObserver
是异步的(包括主流的 setState
等也是),因此要是数据在动画重置时还没有完成更替,可就露馅了,所以我们不妨留点安全边际
例如数据块 A:10条数据,B:5条数据
在滚动到第5条数据不可见时,咱就先对前5条数据进行更替,如此数据在滚动到第10条数据不可见时肯定已经更新完毕,可以放心地重置动画,动画重置后,再对余下的10条数据进行全部更新
浏览器兼容性
绝大多数浏览器是不用担心的了
再不济,咱还有 polyfill
:intersection-observer
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!