Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

基于flex的order实现 carousel 轮播图 #21

Open
eyasliu opened this issue Jun 11, 2018 · 0 comments
Open

基于flex的order实现 carousel 轮播图 #21

eyasliu opened this issue Jun 11, 2018 · 0 comments
Labels

Comments

@eyasliu
Copy link
Owner

eyasliu commented Jun 11, 2018

原因

项目里需要使用轮播图,electron + vue 技术栈,项目应用一旦启动会持续运行24小时,并且机器性能较差,所以很关注两个点

  1. 内存泄漏
  2. 性能

目前社区的轮播组件,大多只是适用于常规 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>

从里面元素开始解释

  1. 父级设置 display: flex ,子级可以通过 order 属性实现排序,这种排序虽然依然会引发重排和重绘,但是开销更小
  2. 外围一层元素,使用 transition 实现 动画,使用 transform 的 translate3d 实现硬件加速与显示范围。在非动画状态,X轴的位置永远都是 0,在动画状态,才给 X轴 赋值,所以整个组件其实就是在做两件事: 顺序X轴位置(也就是动画)
  3. 顺序:非动画状态需要 X 轴一直为0,那么就要保证当前要显示的轮播元素的 order 值最小,我暂时约定最小为 0,因为动画涉及到下一张,所以当前轮播的order 为 0,下一张为 1,其他的只要大于1 即可。
  4. 动画,如果需求是切换的时候不需要动画,那么保证顺序就已经完成了轮播切换了,但需求通常需要动画。动画的实现由三部分,起始状态结束状态重置状态
    1. 起始状态:动画一开始,就是要在当前轮播元素开始,对应的X轴是0,起就是静止状态,所以起止状态不需要设置,默认就是了,所以通常其实状态无需处理
    2. 结束状态:结束的状态是下一张轮播元素完全显示,也就是X增加一个 轮播元素的宽度。动画时间 transition-duration 赋值 500ms,就能实现动画。
    3. 重置状态:动画完成后,重新计算各个元素的 order 值,把 X 轴重设为0,动画时间重设为0

到此就完成了轮播组件的基本功能

功能扩展

自动轮播

先实现一个函数 next() 方法,定时调用

拖动滚动

  1. 记录开始拖动时鼠标位置的 X轴
  2. 移动过程中获取鼠标位置X轴,减去开始拖动时的X轴位置,得到X轴移动的距离,再把这个距离数字赋值给 translate3d 的X轴

反向动画与拖动

通常的轮播都是 从右往左 滚动的,但是有时需要兼容 从左往右,实现方案:

非动画状态无需调整,主要关注动画状态。

  1. 排序:要反过来排序,当前显示的元素 order 为0,下一张为 -1,其他的小于 -1即可
  2. 动画的不同状态都需要调整
  3. 起始状态:X轴位置: -1 * (轮播条数 - 1) * 轮播宽度
  4. 结束状态:X轴位置: -1 * (轮播条数 - 与上条间隔数量) * 轮播宽度
  5. 重置状态:X轴位置:0,排序重置为正向

反向拖动,如果拖动的时候拖动的距离是个正数,则马上更新顺序为反向,如果为负数,马上更新顺序为正向

总结

该方案的性能很高,但是兼容性不太好。而且实现过程中,对元素的排序计算如果涉及到反向动画的话会比较复杂

@eyasliu eyasliu changed the title [草稿]基于flex的order实现 carousel 轮播图 基于flex的order实现 carousel 轮播图 Jun 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant