用JavaScript封装轮播图函数

一. 函数特点

可根据项目需求,自动选择是否自动播放,是否需要左右切换按钮,以及是否需要底部滑块按钮。

二. 函数形参含义

2.1 imgBox:
图片容器,包含所有需要展示图片的盒子(图片浮动排版在该盒子内),需要获取imgBox标签元素,方便复制图片并添加到imgBox里面

2.2 travelDistance:
轮播图滚动一次移动的距离,(imgBoxParent盒子的宽度或者每张图片的宽度)

2.3 imgBoxParent:
imgBox的父盒子,当鼠标放入轮播图时(图片、左右按钮及底部滑块)需要立即停止定时器,不直接用imgBox的原因在于,如果鼠标放在左右按钮和滑块按钮区域时,定时器不会停止,需要获取imgBoxParent标签元素

2.4 timerCode:
是否开启定时器,传入布尔值true or false

2.5 arrows:
是否需要左右切换按钮,若需要则获取arrows的子元素的HTMLCollection元素集合,若不需要则不用传该参数

2.6 slider:
是否需要底部滑块按钮,若需要则获取滑块的的父标签元素slider为参数传入,方便动态创建和添加滑块子元素,若不需要则不用传该参数

2.7 currentActiveColor: 
底部滑块按钮处于活跃时所具有的class类名,传入该参数的类型须为String

三. 函数内容

el.style.left获取的值为字符串且带px,所以用el.style.left给目标盒子赋值,用el.offsetLeft来获取目标盒子距离左侧的距离
// banner.js
function slideShow(imgBox, travelDistance, imgBoxParent, timerCode, arrows, slider, currentActiveColor) {
  // 2.实现无缝轮播的重要条件
  // 复制imgBox盒子里的第一张图片及内容
  let newItemImgBox = imgBox.children[0].cloneNode(true);

  // 并添加到imgBox盒子的尾部以达到无缝轮播的效果
  imgBox.appendChild(newItemImgBox);

  // 3.动态创建滑块按钮,并添加到slider标签元素里面,点亮第一个滑块按钮
  if (slider) {
    // 根据图片的个数创建底部滑块的个数,由于复制了一张图片(该图片只用于无缝衔接),所以需要-1
    for (let i = 0; i < imgBox.children.length - 1; i++) {
      // 创建滑块按钮标签
      let newItemslider = document.createElement('span');

      // 将滑块按钮标签添加到slider标签内
      slider.appendChild(newItemslider);
    }

    // 将第一个滑块置为活跃状态
    slider.children[0].className = currentActiveColor;

    // 鼠标放入滑块时切换显示对应的图片
    for (let j = 0; j < slider.children.length; j++) {
        // 用闭包解决由于是异步操作而无法获取元素对应下标的问题
      slider.children[j].onmouseover = function (el) {
        return function () {
          // 将所有滑块的类名清空
          for (let k = 0; k < slider.children.length; k++) {
            slider.children[k].className = '';
          }

          // 为鼠标所在的当前滑块添加活跃类名
          this.className = currentActiveColor;

          // 根据鼠标所在的位置,同步移动盒子imgBox的位置,以显示对应的图片
          animate(imgBox, - el * travelDistance)

          // 将该下标值同步到currentImgIndex(记录当前显示图片的下标的变量)以及currentSliderIndex(记录当前活跃滑块的下标的变量)
          currentImgIndex = currentSliderIndex = el;
        }
      }(j);
    }
  }

  // 4.是否添加定时器函数部分(默认从左向右切换图片,也就是imgBox向左移动)
  if (timerCode) {
    // 由于let具有块作用域的特性,这里需要使用val,方便其他地方拿取
    var isTimer = setInterval(autoplay, 3000);

      // 记录图片是为了让imgBox根据当前显示的图片,移动相应的距离,记录滑块是为了让当前显示的图片,对应的滑块处于活跃状态
    var currentImgIndex = 0; // 记录当前显示图片的下标
    var currentSliderIndex = 0; // 记录当前活跃滑块的下标

    function autoplay() {
      // 图片部分
      // 每向左移动一次,下标+1,也就是若现在显示的图片为第二张,而该图片的下标是1,currentImgIndex初始值为0,所以需要+1来保持一一对应
      currentImgIndex++;

      // 当滑到最后一张图片的时候(注意最后一张图片和第一张是一样的)
      if (currentImgIndex > imgBox.children.length - 1) {
        // 此时需要移动imgBox位置,让现在显示的是第一张图片,所以imgBox距离imgBoxParent的左边距为0
        imgBox.style.left = 0;

        // 此刻正在显示的是第一张图片,接下来就该第二张了,所以需要将currentImgIndex赋值为1
        currentImgIndex = 1;
      }

      // 调用函数,根据当前显示图片的下标,来让盒子移动相应的位置,否则不管怎么点图片都是不动的
      animate(imgBox, -currentImgIndex * travelDistance);

      // 底部滑块部分
      if (slider) {
        // 每切换一次,下标+1,底部滑块和图片是一一对应的,需要注意的是他们所在的集合长度不一样,因为图片多复制了一张
        currentSliderIndex++;

        // 当前滑块的下标值大于最后一个滑块的下标值时,说明此时到第一张图片了,需要显示第一个滑块,所以currentSliderIndex置为0
        if (currentSliderIndex > slider.children.length - 1) {
          currentSliderIndex = 0;
        }

        // 然后清空所有滑块的类名
        for (let i = 0; i < slider.children.length; i++) {
          slider.children[i].className = '';
        }

        // 给当前的滑块加上活跃类名
        slider.children[currentSliderIndex].className = currentActiveColor;
      }
    }
  }

  // 4.1当鼠标位于imgBoxParent上方时,清除定时器,移开后再开启定时器
  if (imgBoxParent) {
    imgBoxParent.onmouseover = function () {
      clearInterval(isTimer);
    }
    imgBoxParent.onmouseout = function () {
      isTimer = setInterval(autoplay, 3000);
    }
  }

  // 5.左右箭头切换图片部分
  // 5.1 左侧箭头部分
  if (arrows) {
    arrows[0].onclick = function () {
      // 点击左侧按钮时,记录下标值的变量-1
      currentImgIndex--;

      // 当下标值小于0时,说明现在应该显示倒数第二张图片(因为最后一张图片和第一张图片是一样的)
      if (currentImgIndex < 0) {

        // 所以将imgBox距离imgBoxParent左边的距离置为倒数第二张图片距离imgBox左边的距离
        imgBox.style.left = - travelDistance * (imgBox.children.length - 1) + 'px';

        // 并且当前倒数第二张图片的下标值赋给currentImgIndex
        currentImgIndex = (imgBox.children.length - 1) - 1;
      }

      // 调用函数,将盒子imgBox移动到相应的位置
      animate(imgBox, -currentImgIndex * travelDistance)

      // 下面滑块跟着移动部分(如果没传滑块参数,则不执行下面代码)
      if (!slider) return  

      // 点击左侧按钮时,记录滑块的下标跟着变化,每次-1
      currentSliderIndex--;

      // 当下标值小于0时,说明现在应该显示倒数第二张图片(因为最后一张图片和第一张图片是一样的)
      if (currentSliderIndex < 0) {

        // 倒数第二张图片对应的是最后一个滑块,所以将最后一个滑块的下标值赋给currentSliderIndex
        currentSliderIndex = slider.children.length - 1;
      }

      // 循环清空所有滑块的样式
      for (let i = 0; i < slider.children.length; i++) {
        slider.children[i].className = '';
      }

      // 给当前图片对应的滑块添加上活跃样式
      slider.children[currentSliderIndex].className = currentActiveColor;
    }

    // 右侧箭头部分,和定时器运动方向一样(从左到右播放),点击右侧按钮时直接调用函数
    arrows[1].onclick = function () {
      autoplay();
    }
  }

  // 1.盒子从当前值移动到目标值时调用的函数
  function animate(el, target) {
    // 多次点击时,会造成el对应的盒子运动的越来越快,所以需要防抖处理,每次进入函数前先清除它的定时器
    clearInterval(el.Timer);

    // 对比目标位置与盒子当前位置的大小,来决定速度的正反
    let speed = target > el.offsetLeft ? 100 : -100;

    // 为需要移动的盒子el添加定时器
    el.Timer = setInterval(function () {

      // 获取每次移动后距离目标位置剩余的距离
      let value = target - el.offsetLeft;

      // 且把移动的距离赋值给盒子,以达到盒子目前的位置就是其真实的位置
      el.style.left = el.offsetLeft + speed + 'px';

      // 判断距离目标剩余的位置是否够一次步长(一次移动的距离)
      if (Math.abs(value) < Math.abs(speed)) {

        // 如果不够,就直接将目标距离的位置赋值给盒子,并且清除定时器
        el.style.left = target + 'px';

        // 否则永远到不了目标位置
        clearInterval(el.Timer);
      }
    }, 50)
  }
}

四. 实例部分

4.1 代码部分
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 装轮播图片、左右切换按钮以及底部滑块的盒子,也就是方法里面说的imgBoxParent */
    .slide-show-box {
      width: 1200px;
      height: 520px;
      margin: 20px auto;
      overflow: hidden;
      position: relative;
    }

    /* 装轮播图片的盒子 */
    .slide-show-box .imgbox {
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 4800px;
      height: 520px;
    }

    /* 轮播图片 */
    .slide-show-box .imgbox img {
      width: 1200px;
      height: 520px;
      float: left;
    }

    /* 向左切换按钮 */
    .slide-show-box .arrows-l {
      cursor: pointer;
      position: absolute;
      left: 30px;
      top: 224px;
    }

    /* 向右切换按钮 */
    .slide-show-box .arrows-r {
      cursor: pointer;
      position: absolute;
      right: 30px;
      top: 224px;
    }

    /* 底部滑块父盒子元素 */
    .slide-show-box .slider {
      height: 20px;
      position: absolute;
      bottom: 10px;
      left: 500px;
    }

    /* 底部滑块子元素 */
    .slide-show-box .slider span {
      float: left;
      display: block;
      width: 40px;
      height: 10px;
      margin-right: 20px;
      border-radius: 5px;
      background-color: #84a7af;
      cursor: pointer;
    }

    /* 当前活跃滑块的样式 */
    .slide-show-box .slider .activeColor {
      background-color: #ffc0cb;
    }
  </style>
</head>

<body>
  <div class="slide-show">
    <div class="slide-show-box">

      <div class="imgbox">
        <img src="./images/slide_show_one.jpg" alt="">
        <img src="./images/slide_show_two.png" alt="">
        <img src="./images/slide_show_three.jpg" alt="">
      </div>

      <div class="arrows">
        <div class="arrows-l">
          <img src="./images/arrows_l.png" alt="">
        </div>
        <div class="arrows-r">
          <img src="./images/arrows_r.png" alt="">
        </div>
      </div>

      <div class="slider">
      </div>

    </div>
  </div>

  <script src="./banner.js"></script>
  <script>
    let imgBox = document.querySelector('.imgbox')
    let travelDistance = 1200 // 我的图片是1200宽
    let imgBoxParent = document.querySelector(".slide-show-box")
    let timerCode = true
    let arrows = document.querySelectorAll('.arrows')[0].children
    let slider = document.querySelector('.slider')
    let currentActiveColor = 'activeColor'

    // 调用封装的轮播图函数
    slideShow(imgBox, travelDistance, imgBoxParent, timerCode, arrows, slider, currentActiveColor)
  </script>
</body>

</html>
4.2 效果图

在这里插入图片描述

五. 总结

以上即可实现效果,复制代码更改图片即可直接使用。

讨论数量: 0

慎思笃行