怎么去实现一个Swiper组件?

73 阅读2分钟

Swiper组件的作用

使用轮播的动画效果来展示内容。

动画效果实现分析

1. 怎么实现轮播效果?

  • 轮播的效果首先就是内容位置的偏移效果。
  • 可以使用css动画来改变内容的位置。(transform: translate)

2. 如何实现从最后一条内容过渡到第一条内容?

  • 复制第一条内容放在内容列表的尾部,这样最后一条内容往复制的第一条内容的过渡效果同往第一条内容的过渡效果。
  • 过渡完成后立刻取消位置偏移,回到第一条内容。

3. 如何在过渡动画完成后实现停留?

实验了几种方案,下面一一列出,并说明方案的不足。

使用element.animate(keyframes, options)

let animation;
let swiperAnimationResolve;
const keyframes = [];
for (let i = 0; i < sliders.length; i++) {
  // 以纵轴滚动为例
  keyframes.push({ transform: `translateY(-${height * i}px)` });
}
// 先停留一段时间(展示第一条内容),停留完成后开始过渡
// sliderContainer 所有slider的容器元素
animation = sliderContainer.animate([], { delay: 3000 });
animation.addEventListener('finish', swipe);

async function swipe() {
  // 从当前内容往下一条内容过渡
  animation = sliderContainer.animate([keyframes[sliderIndex], keyframes[sliderIndex + 1]], {
    endDelay: 3000, // 过渡完等待
    duration: 1000, // 过渡时间
    fill: 'both',
    iterations: 1 // 动画的重复次数
  });
  // 动画完成(停留完成)后通知开启下一轮
  animation.addEventListener('finish', swiperAnimationResolve);
  // 开始过渡动画和停留
  sliderIndex++;
  // 等待动画结束事件通知,调用swiperAnimationResolve
  await new Promise(resolve => {
    swiperAnimationResolve = resolve;
  });
  // 最后一条往复制的第一条过渡完成
  if (sliderIndex === sliders.length) {
    // 重置位移距离并取消动画
    sliderIndex = 0;
  }
  // 开启下一轮过渡
  return this.swipe();
}

页面进入后台时暂停动画

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    // 暂停动画
    animation.pause();
  } else if (document.visibilityState === 'visible') {
    // 继续动画
    animation.play();
  }
});
// 记得移除事件

取消动画

animation.cancel();

好处

  • js更容易控制
  • 动画的暂停与继续很实时,不像css动画
  • 暂停的时间不会影响设定的时间,由浏览器自己去计算剩余时间。