无缝连接 js轮播图 插件

558 阅读3分钟

无缝连接 js轮播图 插件

初衷

实习考核的时候,按照要求要用vue封装一个轮播图插件, 因为自己之前有过用原生js写过轮播图的经验, 本以为能顺利实现, 但是还是遇到了问题 —— 无缝连接。然后自己网上各种的查找无缝连接的实现原理, 都大同小异, 然而当自己去用代码实现的时候, 却不能达到想要的效果, 就这样查查改改实现下来, 发现了** 关键问题 ** 所在, 于是整理了自己的思路, 用 ** 原生js ** 实现一下。

效果

效果展示图

原理

两个关键点

  • DOM 结构

    • 末尾重复第一张, 开头重复最后一张图

轮播结构图

  • 临界处理

    • 向右滚动到第 1 张(最右边)的时候, **取消过渡效果 *, ** 并迅速复原位置 ** (最左边第 1 张) * 见代码

    • 向左滚动到第 3 张(最左边)的时候, **取消过渡效果, ** 并迅速复原位置 ** (最右边第 3 张)

功能

  • 无缝连接, 自动播放

  • 循环播放设置

  • 过渡动画设置

  • 左右箭头切换下一张

  • 指示器切换

代码

html

  <!-- 因为写的是插件, dom 结构是js动态添加, 这里只是展示添加过后的主要结构 -->
<div id="carousel-wrapper">
      <ul class="carousel__list">
        <li><img src="./images//carousel_03.webp" alt="" /></li>

        <li><img src="./images//carousel_01.webp" alt="" /></li>
        <li><img src="./images//carousel_02.webp" alt="" /></li>
        <li><img src="./images//carousel_03.webp" alt="" /></li>

        <li><img src="./images//carousel_01.webp" alt="" /></li>
      </ul>
    </div>

js

  • 创建Carousel轮播图对象
function Carousel(el, option) {
  this.el = el; // 挂在dom 对象
  this.images = option.images; // 图片数组
  // ?? 与 || 运算符相同, 区别是如果 ?? 前值是false也能取到, ||取不到
  this.autoPlay = option.autoPlay ?? true; // 是否自动播放
  this.loop = option.loop ?? true; // 是否循环播放
  this.easing = option.easing || "ease"; // 动画效果

  this.list = null; // 轮播图对象
  this.indic = null; // 指示器wrapper
  this.indics = []; // 指示器
  this.len = this.images.length; 
  this.elWdith = this.el.offsetWidth; // 轮播图宽度
  this.timer = null;

  this.currentIndex = 1; // 当前显示图片索引

  this.init();
}
  • 初始化

    dom结构初始化和事件绑定初始化

Carousel.prototype.init = function () {
  // 初始化dom 结构
  this.initDom();
  // 初始化事件绑定
  this.initEvent();
  // 是否自动播放
  this.autoPlay && this.autoMove();
};
  • *移动函数 (重点) *

    使用setTimeout,延迟代码块执行,** 延迟执行的时间必须和过渡的时间相同 **

    后面的切换事件的** 公用函数 **

Carousel.prototype.move = function () {
  // 右临界值处理
  if (this.currentIndex >= this.len + 1) {
  
    /* 当 this.currentIndex = 4 时, 此时不会立即执行这块代码,复原位置,
    而是执行最下面的代码, 滚动到第 1 张(最后的 1 ) 时,才执行, 因为没有了过渡, 用户看不到真正滚动了, 其实这时候已经已经到第 1 张 ( 开始的 1 ) */
    
    setTimeout(
      function () {
        this.list.style.transition = null; // 清除过渡效果
        this.currentIndex = 1; // 重置索引
        this.list.style.transform = `translateX(${-this.elWdith}px)`; // 重置位置
      }.bind(this),
      1000
    );
  }

 // 左临界值处理
if (this.currentIndex <= 0) {
  setTimeout(
    function () {
      this.list.style.transition = null;
      this.currentIndex = this.len;
      this.list.style.transform = `translateX(${-this.elWdith * this.len}px)`;
    }.bind(this),
    1000
  );
  }

// 先执行此处代码
this.list.style.transition = `all 1s ${this.easing}`; // 开启过渡效果
this.list.style.transform = `translateX(${ 
  -this.currentIndex * this.elWdith
}px)`;
};
  • 自动移动播放
//自动移动
Carousel.prototype.autoMove = function () {
  const that = this; 

  this.timer = setInterval(function () {
    that.currentIndex++;
    that.move();
  }, 2000);
};
  • 其他方法
// 切换上一张
Carousel.prototype.pre = function () {
  this.currentIndex--;
  this.move();
}; 

// 切换下一张
Carousel.prototype.next = function () {
  this.currentIndex++;
  this.move();
};

// 暂停播放
Carousel.prototype.pausePlay = function () {
  clearInterval(this.timer);
};

Carousel.prototype.initDom // 初始化dom 结构
Carousel.prototype.initEvent // 事件绑定

bug 解决

滚动到临界值处, 在过渡时间内点击切换按钮, 以及短时间内连续点击切换, 会出现闪动或者轮播卡顿。使用节流函数优化点击事件

/**
 * 节流函数
 * @param { Number } wait 等待多长执行 尽量和过渡动画时间接近
 * @param { Function } fn 回调函数
 * @return {}
 */
let pre = 0; // 开始时间
const throttle = function (wait, fn) {
  return function () {
    const context = this;
    let args = arguments;
    const now = Date.now(); // 返回自 1970 年 1 月 1 日 00:00:00  到当前时间的毫秒数。
    if (now - pre > wait) {
      fn.call(context, args);
      pre = now;
    }
  };
};

插件使用

 <!-- 1. 引入 样式文件  -->
 <link rel="stylesheet" href="./style.css" />
 <!-- 2. 引入 js  -->
 <script src="./index.js"></script>
 
 var wrapper = document.getElementById("carousel-wrapper");
 
  //  3. 实例化Carousel对象, 传入参数
  /*
   * 第一个参数为挂载的dom对象, 必须传
   * 第二个参数: 配置对象{}
   *   images: 轮播的图片数组, 每张图片是一个对象, 必须包含src 属性
   *   autoPlay: 是否自动播放, 默认true
   *   arrow: 是否显示箭头切换按钮, 默认true
   *   indicator: 是否显示指示器, 默认true
   *    easeing: 过度效果, 默认为 ease
   */
  new Carousel(wrapper, {
    images: [
      { src: "./images//carousel_01.webp", alt: "" },
      { src: "./images//carousel_02.webp", alt: "" },
      { src: "./images//carousel_03.webp", alt: "" },
    ],
    easing: "ease",
    loop: true,
    autoPlay: true,
  });

写在最后

根据自己的思路去实现出来, 发现问题, 解决问题, 对自己是一个很大的提升。 需要完整源码的可以私我, 感谢大家的支持。发现问题请及时向我提出。