原因
项目里需要使用轮播图,electron + vue 技术栈,项目应用一旦启动会持续运行24小时,并且机器性能较差,所以很关注两个点
- 内存泄漏
- 性能
目前社区的轮播组件,大多只是适用于常规 web 应用,经过内部测试后,并不能满足内存和性能方面的要求,所以需要自己实现轮播组件
思路
最开始找到了这篇文章,里面讲解了传统的轮播图实现思路和作者原创的轮播思路,并在文末给出了性能较高的原创方案。
作者的原创方案性能是很高了,但是我注意到每次执行轮播都需要移动一个 DOM 节点,这会触发浏览器重排重绘,性能依旧不够高,还可以继续优化。
首先想到了 flex 布局的 order 属性:https://developer.mozilla.org/zh-CN/docs/Web/CSS/order
兼容性
可以看到只有现代浏览器才支持,如果要兼容老久浏览器就不用考虑本方案了,我的环境是electron 2.0,集成的chrome 61,可使用。
实现方案
本文章只记录实现方案与伪代码,不会给出 demo。
基本功能实现
html结构
<div class="carousel">
<div class="carousel-container" style="transition-duration: 0ms; transform: translate3d(0px, 0px, 0px);">
<!-- 轮播列表元素 -->
<div class="carousel-item" style="order: 0;"></div>
<div class="carousel-item" style="order: 1;"></div>
<div class="carousel-item" style="order: 2;"></div>
<div class="carousel-item" style="order: 3;"></div>
<div class="carousel-item" style="order: 4;"></div>
</div>
</div>
<style>
.carousel {
width: 100%;
}
.carousel-container {
width: 100%;
display: flex;
transition-property: transform;
}
.carousel-item {
width: 100%;
}
</style>
从里面元素开始解释
- 父级设置 display: flex ,子级可以通过 order 属性实现排序,这种排序虽然依然会引发重排和重绘,但是开销更小
- 外围一层元素,使用 transition 实现 动画,使用 transform 的 translate3d 实现硬件加速与显示范围。在非动画状态,X轴的位置永远都是 0,在动画状态,才给 X轴 赋值,所以整个组件其实就是在做两件事: 顺序 与 X轴位置(也就是动画)
- 顺序:非动画状态需要 X 轴一直为0,那么就要保证当前要显示的轮播元素的 order 值最小,我暂时约定最小为 0,因为动画涉及到下一张,所以当前轮播的order 为 0,下一张为 1,其他的只要大于1 即可。
- 动画,如果需求是切换的时候不需要动画,那么保证顺序就已经完成了轮播切换了,但需求通常需要动画。动画的实现由三部分,起始状态 、结束状态、重置状态
- 起始状态:动画一开始,就是要在当前轮播元素开始,对应的X轴是0,起就是静止状态,所以起止状态不需要设置,默认就是了,所以通常其实状态无需处理
- 结束状态:结束的状态是下一张轮播元素完全显示,也就是X增加一个 轮播元素的宽度。动画时间
transition-duration
赋值500ms
,就能实现动画。 - 重置状态:动画完成后,重新计算各个元素的 order 值,把 X 轴重设为0,动画时间重设为0
到此就完成了轮播组件的基本功能
功能扩展
自动轮播
先实现一个函数 next()
方法,定时调用
拖动滚动
- 记录开始拖动时鼠标位置的 X轴
- 移动过程中获取鼠标位置X轴,减去开始拖动时的X轴位置,得到X轴移动的距离,再把这个距离数字赋值给
translate3d
的X轴
反向动画与拖动
通常的轮播都是 从右往左 滚动的,但是有时需要兼容 从左往右,实现方案:
非动画状态无需调整,主要关注动画状态。
- 排序:要反过来排序,当前显示的元素 order 为0,下一张为 -1,其他的小于 -1即可
- 动画的不同状态都需要调整
- 起始状态:X轴位置:
-1 * (轮播条数 - 1) * 轮播宽度
- 结束状态:X轴位置:
-1 * (轮播条数 - 与上条间隔数量) * 轮播宽度
- 重置状态:X轴位置:0,排序重置为正向
反向拖动,如果拖动的时候拖动的距离是个正数,则马上更新顺序为反向,如果为负数,马上更新顺序为正向
总结
该方案的性能很高,但是兼容性不太好。而且实现过程中,对元素的排序计算如果涉及到反向动画的话会比较复杂