资讯专栏INFORMATION COLUMN

ES6! 如何制作一个高效轮播图?

Simon / 1653人阅读

摘要:你的网站真的需要一个轮播图吗轻轻问自己三声,谷歌一下对轮播图效果的相关调查和建议,再决定是否要着手制作你的轮播图。在接近块间距时关闭动画移至另一块相应位置。表示接近边缘的图片。可把一部分放到里或轮播图前,阻塞渲染。

轮播图千种万种,怎样才能做出符合要求的轮播图?原理上天入地,如何优化才能达到极限丝滑?本文作者将解答这一切,通过现场制作一个轮播图,带你详细了解、理解,制作 All kinds of 高性能轮播图 !

仿自 Google Play

不过,在事实上,轮播图的点击率通常都很低,很少能引起用户的注意,而却往往占用了页面某个极重要的位置。你的网站真的需要一个轮播图吗?轻轻问自己三声,谷歌一下对轮播图效果的相关调查和建议,再决定是否要着手制作你的轮播图。

2017.8.20 更新——————————
1. 代码简洁化 & 语言精简
2. 删去不被推荐的有限部分
3. API 重写

! ES6 API 重写
ES6 啊,,牛逼啊!我TM要火啊!!
然而并没有。

开始

1. 结构

div.father包裹图片。div.viewport为视口部分。

A
B
C
D
E
.viewport {
  width: 900px;
  height: 300px;
  overflow: hidden;
  position: relative;
}
.father {
  height: inherit;
  width: 3000%; /* 子元素 float 无法撑开 */
  transform: translate3d(0, 0, 0);
  transition: transform 0.3s ease-in-out;
}
.father > div {
  width: 550px;
  height: inherit;
  float: left;
}
.mother {
  width: 30px;
  height: inherit;
  line-height: 300px;
  text-align: center;
  cursor: pointer;
  user-select:none;
  background: rgba(0,0,0,0.15);
  position: absolute;top: 0;
} .mother.left { left: 0 } .mother.right { right: 0 }

transform: translate3d()使用 GPU 加速。

2. 代码实现

class Lunbo {
  constructor(element) {
    this.viewport = element;
    this.father = element.children[0];
    this.photos = this.father.children;
    // 自设的图片宽, 包括 margin
    this.photoWidth = this.photos[0].offsetWidth + parseInt(getComputedStyle(this.photos[0]).marginLeft) + parseInt(getComputedStyle(this.photos[0]).marginRight);

    // 注册移动事件
    element.children[1].addEventListener("click", this.left.bind(this));
    element.children[2].addEventListener("click", this.right.bind(this));
  }

  load() {

  }

  left() {
    this.load(this.showingId - 1);
  }

  right() {
    this.load(this.showingId + 1);
  }
}

页面加载时:选取一张作为焦点
切换时fatherGo(to)负责跳转到指定的焦点图;

高效 & 无限轮播

(此处以下所有代码仅显示添加 / 修改部分)
思路也是难点。一题,这样解决:

class Lunbo {
  constructor(element) {
    // (可视宽 -焦点图片宽) / 2,焦点图到视口左或右的距离
    this.partnerWidth = (this.viewport.clientWidth - this.photoWidth) / 2;
  }

  // 计算移动距离
  countX(id) {
    return -id * this.photoWidth + this.partnerWidth;
  }

  // 切换 / 载入 / 移动图片。无参数则除法求整,仅用来切换到一个瞎选的初始焦点
  load(newId = parseInt(this.photos.length / 2) - 1) {
    this.father.style.transform = `translate3d(${this.countX(newId)}px, 0, 0)`;
    this.showingId = newId;
  }
}
// 切换至初始焦点
const Example = new Lunbo(document.getElementById("example"));
Example.load();

countX(id) 解释:

若将 Id = 2 对应图片(第 3 张)作焦点,向左挪过去两张(此时该图靠最左),后加回partnerWidth

二题:

A
B
C
D
E
A
B
C
D
E
A
B
C
D
E

三倍于展示图,JS 动态生成亦可。称之三个块。

.moving { transition: none }

接近块间距时关闭动画移至另一块相应位置。

class Lunbo {
  constructor(element) {
    // 表示接近边缘的图片 Id。接近左边缘的即第2 张图,右边缘的则为倒数第二张
    this.closeLeftId = 1;
    this.closeRightId = this.photos.length - 2;

    this.photosQuantity = this.photos.length / 3;

    // 当运动到上面两个 Id 时默默移动到的对应 Id
    // 接近左边时跳转到右边块的第二张
    // 接近右边则跳转到左边块的倒数第二张
    this.backLeftId = this.photosQuantity - 2;
    this.backRightId = this.photosQuantity * 2 + 1;
  }

  load(newId = parseInt(this.photos.length / 2) - 1) {
    this.father.style.transform = `translate3d(${this.countX(newId)}px, 0, 0)`;

    if (newId === this.closeLeftId){
      newId = this.backRightId;
    } else if (newId === this.closeRightId){
      newId = this.backLeftId;
    } else {
      this.showingId = newId;
      return;
    }
    this.father.addEventListener("transitionend", this.backMove.bind(this, newId), {once: true});
  }

  backMove(newId) {
    this.father.classList.add("moving");
    this.father.clientWidth();
    this.father.style.transform = `translate3d(${this.countX(newId)}px, 0, 0)`;
    this.father.clientWidth();
    this.father.classList.remove("moving");
    this.showingId = newId;
  }
}

4. 整理代码


17.8.20

A
B
C
D
E
A
B
C
D
E
A
B
C
D
E

代码已通过测试。你需要码更多的代码,兼容各个浏览器,以及让它可以被更好地维护,然后做得更好(装)看(B)一些。

高级选项

一味把

阅读需要支付1元查看
<