Skip to content
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html, body {
      height: 100%;
      overflow: hidden;
    }

    .container {
      width: 1226px;
      height: 460px;
      margin: 0 auto;
      position: relative;
      box-sizing: border-box;
      overflow: hidden;
    }

    .container .wrapper {
      position: absolute;
      top: 0;
      left: 0;
      width: 6130px; /* calc(1226px * 5); */
      height: 100%;
      transition: left linear;
    }

    .container .wrapper .slide {
      float: left;
      width: 1226px;
      height: 100%;
      background: #eee;
    }

    .container .wrapper .slide img {
      width: 100%;
      height: 100%;
      display: block;
      cursor: pointer;
    }

    .container .pagination {
      width: 400px;
      height: 21px;
      position: absolute;
      right: 38px;
      bottom: 20px;
      text-align: right;
      user-select: none;
    }

    .container .pagination span {
      width: 8px;
      height: 8px;
      display: inline-block;
      border: 2px solid #fff;
      border-color: hsla(0, 0%, 100%, .3);
      border-radius: 10px;
      background: rgba(0, 0, 0, .4);
      opacity: .8;
      transition: all .2s;
      cursor: pointer;
    }

    .container .pagination span.active {
      background: rgba(255, 255, 255, .4);
      border-color: rgba(0, 0, 0, .4);
      transform: scale(1.2);
    }

    .container .navigation div {
      width: 41px;
      height: 69px;
      display: block;
      position: absolute;
      top: 196px; /* calc(460px / 2 - 69px / 2) */
      background: url('./imgs/navigation.png') no-repeat;
    }

    .container .navigation .button-prev {
      background-position-x: -83px;
    }

    .container .navigation .button-prev:hover {
      background-position-x: 0px;
    }

    .container .navigation .button-next {
      right: 0;
      background-position-x: -124px;
    }

    .container .navigation .button-next:hover {
      background-position-x: -41px;
    }
  </style>
</head>
<body>
  <section class="container">
    <!-- 轮播图 -->
    <div class="wrapper">
      <div class="slide">
        <img src="./imgs/1.jpg" alt="">
      </div>
      <div class="slide">
        <img src="./imgs/2.webp" alt="">
      </div>
      <div class="slide">
        <img src="./imgs/3.webp" alt="">
      </div>
      <div class="slide">
        <img src="./imgs/4.webp" alt="">
      </div>
      <div class="slide">
        <img src="./imgs/1.jpg" alt="">
      </div>
    </div>

    <!-- 分页器 -->
    <div class="pagination">
      <span class="active"></span>
      <span></span>
      <span></span>
      <span></span>
    </div>

    <!-- 导航按钮 -->
    <div class="navigation">
      <div class="button-prev"></div>
      <div class="button-next"></div>
    </div>
  </section>

  <script>
    const bannerModule = (function () {
      let container = document.querySelector('.container')
        wrapper = container.querySelector('.wrapper'),
        pagination = container.querySelector('.pagination'),
        navigation = container.querySelector('.navigation')
        slideList = wrapper.querySelectorAll('.slide'),
        paginationList = pagination.querySelectorAll('span'),
        paginationList = Array.from(paginationList),
        prev = navigation.querySelector('.button-prev'),
        next = navigation.querySelector('.button-next'),
        slideListLength = slideList.length,
        paginationListLength = paginationList.length,
        index = 0, // 当前slide索引
        indexBackUp = null, // 当前slide索引备份
        delay = 1000, // 轮播时间
        timer = null // 定时器返回值(定时器有返回值,是一个数字,代表当前是第几个定时器,清除的时候根据这个号码清除)
  
      // 轮播
      const autoPlay = function autoPlay () {
        if (index >= slideListLength - 1) {
          // 要从克隆那张图片跳转到用户眼里的第二张图片,先让克隆那张图片立即跳转到用户
          // 眼里的第一张图片
          wrapper.style.transitionDuration = '0s'
          wrapper.style.left = '0px'
          //基于获取样式刷新渲染队列
          wrapper.offsetLeft
          // 跳转后更新索引,之后由于index++,会跳转到用户眼里看到第二张图片
          index = 0
        }

        // index++之前如果等于slideListLength - 2,说明是用户眼里看到的最后一张图片
        // (后面还有一张克隆的)
        index++ 
        // index++之后是克隆的那张图片,也给用户看,此时用户眼里看到的是第一张图片,进入下一轮循环
        wrapper.style.transitionDuration = '.3s'
        wrapper.style.left = -1226 * index + 'px'
        // 对齐分页器
        paginationFocus()
      }

      // 开始轮播
      const startPlay = function startPlay () {
        timer = setInterval(autoPlay, delay)
      }

      // 分页器对齐
      const paginationFocus = function paginationFocus () {
        indexBackUp = index
        indexBackUp === slideListLength - 1 ? indexBackUp = 0 : null
        paginationList.forEach((item, idx) => {
          if (indexBackUp === idx) {
            // 选中的添加样式
            item.classList.add('active')
            return
          }
          // 其他的移除样式
          item.classList.remove('active')
        })
      }

      // 鼠标进入容器,停止轮播/鼠标离开容器,开始轮播
      const handleMouse = function handleMouse () {
        container.onmouseenter = function () {
          clearInterval(timer)
        }
        container.onmouseleave = function () {
          startPlay()
        }
      }

      // 点击分页器切换图片
      const handlePagination = function handlePagination () {
        for(let i = 0; i < paginationListLength; i++) {
          let item = paginationList[i]
          item.onclick = function () {
            // 如果点击当前图片的分页器或者显示的是克隆那张时点击第一个分页器不做处理
            if (index === i || (index === slideListLength - 1 && i === 0)) {
              return
            }
            index = i
            wrapper.style.transitionDuration = '.3s'
            wrapper.style.left = -1226 * index + 'px'
            // 切换玩对齐分页器
            paginationFocus()
          }
        }
      }
      
      const handleNavigation = function navigation () {
        // 点击右导航按钮功能和自动轮播的功能一样,都是切换到下一张
        next.onclick = autoPlay

        // 点击左导航按钮切换
        prev.onclick = function () {
          if (index <= 0) {
            index = 4
            wrapper.style.transitionDuration = '0s'
            wrapper.style.left = -1226 * index + 'px'
            wrapper.offsetLeft
          }
          index--
          wrapper.style.transitionDuration = '.3s'
          wrapper.style.left = -1226 * index + 'px'
          paginationFocus()
        }
      }

      return {
        init () {
          startPlay()
          handleMouse()
          handlePagination()
          handleNavigation()
        }
      }
    })()

    bannerModule.init()
  </script>
</body>
</html>