JS原生实现轮播图

JS原生实现轮播图

前端新人的练习,希望能对同为小白的小伙伴有所帮助。
欢迎大佬们指正,欢迎大家讨论

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Rotation Chart</title>
	<!-- js原生实现轮播图 -->
    <!-- 
    整体思路: 
    1.全局设置一个总定时器,控制自动轮播,该功能要返回一个定时器标志以便后续控制它
    2.定时器终止:hover或按钮点击事件发生,清除当前定时器,轮播暂停
    3.点击事件响应完毕(或没有点击事件在被响应)后、且鼠标已移出图片框,新建定时器继续轮播
    4.点击事件响应:事件委托,统一处理点击事件
    5.图片的移动由一个公共函数完成,被轮播和按钮响应事件共用


    总的,需要:
    一个图片移动函数
    一个轮播函数,
    一个开启轮播函数、一个结束轮播函数
    
   需要处理的事件有:
   鼠标hover事件、out事件,导航按钮点击事件

    -->
    <!-- 功能:
    自动轮播、hover暂停轮播,
    点击按钮切换图片(短时间的多次点击只以第一次点击为准,图片移动结束后才会响应新的点击)
    均已实现,
	可能还是有bug,欢迎大佬们指正,欢迎大家讨论
    -->
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      #imageList {
        width: 620px;
        height: 390px;
        background-color: rgb(91, 100, 99);
        margin: auto;
        margin-top: 60px;
        position: relative;
        overflow: hidden;
      }
      /* 开启图片的绝对定位,方便后面JS将图片横向排布进行轮播 */
      #images {
        position: absolute;
      }
      li {
        list-style: none;
        padding: 0;
        margin: 0;
        float: left;
      }
      img {
        width: 600px;
        height: 370px;
        margin: 10px;
      }
      /* 导航按钮栏位置:(不定宽高居中) */
      #buttonBox {
        position: absolute;
        left: 50%;
        top: 340px;
      }
      #buttons {
        position: relative;
        left: -50%;
      }
      #buttons li {
        padding-right: 15px;
      }
      /* 导航按钮样式(选择了浮动,因为浮起来就是块元素了,方便调整其样式): */
      #buttons a {
        float: left;
        width: 10px;
        height: 10px;
        /* opacity: 0.5; */
      }
      /* 按钮修改前后样式 */
      .beforeChange {
        background-color: rgb(240, 219, 29);
        opacity: 0.5;
      }
      .afterChange {
        background-color: rgb(255, 247, 220);
        opacity: 0.8;
      }
      #buttons a:hover {
        background-color: rgb(255, 255, 255);
      }
    </style>
  </head>
  <body>
    <div id="imageList">
      <ul id="images" class="infiniteRotation stranslateMove">
      	<!-- 这里的图片需要换成自己的路径 -->
        <li class="img"><img src="img/1.jpg"/></li>
        <li class="img"><img src="img/2.jpg"/></li>
        <li class="img"><img src="img/3.jpg"/></li>
        <li class="img"><img src="img/4.jpg"/></li>
        <li class="img"><img src="img/5.jpg"/></li>
        <li class="img"><img src="img/1.jpg"/></li>
      </ul>
      <div id="buttonBox">
        <ul id="buttons">
          <li><a href="javascript:;" class="beforeChange"></a></li>
          <li><a href="javascript:;" class="beforeChange"></a></li>
          <li><a href="javascript:;" class="beforeChange"></a></li>
          <li><a href="javascript:;" class="beforeChange"></a></li>
          <li><a href="javascript:;" class="beforeChange"></a></li>
        </ul>
      </div>
    </div>
    <script>
      // 获取图片和导航钮对象组;
      var imgs = document.getElementsByClassName("img");
      var aS = document.getElementsByTagName("a");
      var aLen = aS.length;
      var iLen = imgs.length;

      var buttons = document.getElementById("buttons");
      var images = document.getElementById("images");

      // 设置图片框整体大小
      images.style.width = iLen * 620 + "px";

      // 图片依次左右排列
      for (let i = 0; i < iLen; i++) {
        imgs[i].style.left = i * 620 + "px";
      }
      // 为按钮设置索引:
      for (let i = 0; i < aLen; i++) {
        aS[i].index = i;
      }

      // 设置点击事件后按钮样式的函数:
      function setA(obj, lastObj) {
        if (lastObj) {
          lastObj.classList.remove("afterChange"); //将上一次按下的按钮恢复
        }
        obj.classList.add("afterChange"); //将此次按下的按钮点亮(点亮后的class覆盖了平常状态的class)
        return obj;
      }

      setA(aS[0]); //第一个按钮在初始时应当时点亮状态
      var lastClickA = aS[0]; //设置lastClickA变量接收上一次被点击的按钮对象

      // 需要一个返回图片是否已到达指定位置的状态变量:
      var arrive = true;

      //为解决动画会产生大量不可控定时器的问题,引入以下函数,timeout可以实时关掉自己,避免出现多个定时器
      // 以下是动画函数:
      function move(nowLeft, target) {
        var speed = 20;
        if (nowLeft > target) {
          speed = -speed;
        }
        var next = nowLeft + speed;
        function littlemove(next) {
          //移动的一小步函数,循环这个函数实现整体的移动
          var timeout = setTimeout(function () {
            images.style.left = next + "px";
            next = next + speed;
            clearTimeout(timeout);
            if (next != target + speed) {
              //当到达了图片目标位置就不再循环
              littlemove(next);
            }
            if (next == target + speed) {
              //到达目的位置才修改arrive变量值
              arrive = true;
              console.log(rotation);

              //之前存在图片移动过程中鼠标移出图片框范围导致轮播重启被拦截、失效的问题
              //这里添加一个判断,当总定时器不存在时意味着现在是非轮播状态,该状态下图片结束移动后重启定时器,继续
              if (!rotation) {
                start();
              }
              if (images.offsetLeft / -620 == iLen - 1) {
                lastClickA = setA(aS[0], lastClickA);
              } else {
                lastClickA = setA(aS[images.offsetLeft / -620], lastClickA);
              } //不管中间怎么按,最后还是会点亮显示的图片对应的按钮
            }
          }, 50);
        }
        if (arrive == true) {
          arrive = false;
          littlemove(next); //无点击事件
        }
      }

      //自动轮播函数
      function rotationSelf() {
        nowLeft = images.offsetLeft;
        if (nowLeft <= -(iLen - 1) * 620) {
          images.style.left = 0;
          lastClickA = setA(aS[0], lastClickA);
        } else {
          move(nowLeft, nowLeft - 620);
          if (nowLeft == -(iLen - 2) * 620) {
            lastClickA = setA(aS[0], lastClickA);
          } else {
            lastClickA = setA(aS[nowLeft / -620 + 1], lastClickA);
          }
        }
      }

      var rotation; //全局定时器声明,方便后续其它事件发生时对自动轮播功能进行处理(暂停再开启等)

      function start() {
        rotation = setInterval(function () {
          //全局定时器,控制自动切换
          if (images.offsetLeft % 620 == 0) {
            //当图片移动到恰好的位置时才进行停顿
            rotationSelf.call(images);
          }
        }, 1000);
      }

      function stop() {
        //停止轮播函数
        clearInterval(rotation);
      }

      //导航钮功能实现(这里不需要考虑重新开启定时器的问题,鼠标移到图片外时会自动开启轮播):
      function guide(index) {
        stop();
        rotation = undefined;
        lastClickA = setA(aS[index], lastClickA);
        move(images.offsetLeft, index * -620);
      }

      // 下面是函数执行、事件响应处理:

      start(); //初始状态应当是轮播开启的状态

      //点击导航钮和鼠标hover时停止轮播,图片切换后以及鼠标移开后图片继续轮播
      //先解决hover:
      images.onmouseover = function () {
        stop();
      };

      //这里需要考虑导航按钮触发的图片移动是否已经结束:
      images.onmouseout = function () {
        if (arrive) {
          console.log(arrive);
          start();
        }
      };

      //事件委托(导航按钮点击事件响应)
      buttons.onclick = function (event) {
        let clickedA = event.target;
        if (clickedA.nodeName == "A") {
          //重复点击拦截:
          //当一个按钮处于被选中状态下时,再次点击它或者点击其它按钮都是不起作用的,
          //只有结束了当前移动才会开启新的响应:
          if (arrive) {
            guide(clickedA.index);
          }
        }
      };
    </script>
  </body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值