• 原生JS轮播-各种效果的极简实现(二)面向对象版本的实现和优化


    之前写了一篇原生JS轮播,不过是非面向对象的,并且也没有添加上自动轮播。这里来写一下如何优化和进阶。

    这里简单地介绍一下之前的代码,这是html结构

    <body>
      <div class="wrap">
        <ul class="pic-group">
          <li><img src="./pic1.jpg" alt=""></li>
          <li><img src="./pic2.jpg" alt=""></li>
          <li><img src="./pic3.jpg" alt=""></li>
          <li><img src="./pic4.jpg" alt=""></li>
          <li><img src="./pic5.jpg" alt=""></li>
        </ul>
        <ol class="num-group">
          <li class="current">1</li>
          <li>2</li>
          <li>3</li>
          <li>4</li>
          <li>5</li>
        </ol>
      </div>
    </body>
    

    css结构

    <style type="text/css">
        * {
          margin: 0;
          padding: 0;
        }
        ul, li {
          list-style: none;
        }
        body {
          background-color: #000;
        }
        .wrap {
          position: relative;
          border: 8px solid #fff;
          margin: 100px auto;
           400px;
          height: 250px;
          overflow: hidden;
        }
        .pic-group {
          position: absolute;
        }
        .pic-group li img {
          display: block;
           100%;
          height: 100%;
        }
        .num-group {
          position: absolute;
          bottom: 5px;
          right: 0;
          height: 20px;
        }
        .num-group li {
          float: left;
           20px;
          height: 20px;
          line-height: 20px;
          font-size: 10px;
          margin-right: 10px;
          background-color: #089e8a;
          color: #eee;
          text-align: center;
          border-radius: 10px;
          cursor: pointer;
          opacity: 0.8;
        }
        .num-group li:hover {
          box-shadow: 0 0 18px #000;
        }
        .num-group li.current {
          opacity: 1;
          color: #089a8a;
          background-color: #000;
        }
      </style>
    

    JS 结构

    const oImage = document.getElementsByClassName("pic-group")[0];
    const oNumber = document.getElementsByClassName("num-group")[0];
    const numList = oNumber.getElementsByTagName("li");
    for (let i = 0; i < numList.length; i++) {
      numList[i].onmouseover = () => {
        clearNumState();
        show(i);
      }
    }
    const clearNumState = () => {
      for (const item of numList) {
        item.className = "";
      }
    }
    let timer = null;
    const show = (index) => {
      numList[index].className = "current";
      if (timer) clearInterval(timer);
      const target = -250 * index;
      let now = oImage.offsetTop;
      timer = setInterval(() => {
        if (now === target) {
          clearInterval(timer);
        } else {
          now += move(target);
          oImage.style.top = now + "px";
          console.log(oImage.offsetTop);
        }
      }, 20);
    }
    const move = (target) => {
      // 当前值
      const now = oImage.offsetTop;
      const differ = target - now;
      console.log(differ / 10);
      const res = differ > 0 ? Math.ceil(differ / 10) : Math.floor(differ / 10);
      return res;
    }
    

    进阶1:我们可以通过offsetHeight获取图片元素的高度。好处1是我们的移动函数不用限死。也为后来将其变为通用的一组代码做铺垫。

    这里遇到一个不该出现的问题。常常我们看到直接获取高度的时候是 0,原因是:一些元素是根据内容的高度自动调整的,即所谓的自适应高度,它的高度取决于内容的多少。
    获取这样的自适应高度元素主要有两种办法
    • currentStyle
    • offsetHeight
    但用在这里我的offsetHeight竟然是0?不是说好了能获取自适应高度的吗!
    const oHeight = oImage.getElementsByTagName("li")[0].offsetHeight;
    console.log(oHeight);   // 0 !!! 0 !!!
    
    经过我的发现,我知道了问题出在这里?JS代码跑完了?但是图片是否加载完毕了呢?
    window.onload = function() {
      const oT = document.getElementsByClassName("pic-group")[0];
      const oI = oT.getElementsByTagName("li");
      console.log(oI[0].offsetHeight);   // 250
    }
    
    图片没有加载完。当然这里还有一个疑问,为什么控制台有了答案?(这个留待以后探究)

    https://www.cnblogs.com/hanxingli/p/5513116.html
    这里第 5 句 正是解答,图片还在加载中,先执行了代码。

    那么,解决方案是什么呢?

    我们需要的是等图片加载完后执行JS的办法
    http://www.jb51.net/article/79233.htm

    思前想后,这只是个简单的轮播,我选择了window.onload,还有一个不太破坏代码的是async/await,可是那需要加载新的库支持,所以这里选择了最开始的window.onload

    进阶2:添加自动轮播,同时,我们也可以发现,clearNumState应该放在show函数里面

    const oImage = document.getElementsByClassName("pic-group")[0];
    const oNumber = document.getElementsByClassName("num-group")[0];
    const numList = oNumber.getElementsByTagName("li");
    const imageList = oImage.getElementsByTagName("li");
    const oHeight = imageList[0].offsetHeight;
    for (let i = 0; i < numList.length; i++) {
      numList[i].onmouseover = () => {
        // clearNumState();
        show(i);
      }
    }
    const clearNumState = () => {
      for (const item of numList) {
        item.className = "";
      }
    }
    let timer = null;
    const show = (index) => {
      clearNumState();
      numList[index].className = "current";
      if (timer) clearInterval(timer);
      const target = -oHeight * index;
      let now = oImage.offsetTop;
      timer = setInterval(() => {
        if (now === target) {
          clearInterval(timer);
        } else {
          now += move(target);
          oImage.style.top = now + "px";
          console.log(oImage.offsetTop);
        }
      }, 20);
    }
    const move = (target) => {
      const now = oImage.offsetTop;
      const differ = target - now;
      console.log(differ / 10);
      const res = differ > 0 ? Math.ceil(differ / 10) : Math.floor(differ / 10);
      return res;
    }
    let autoTimer = null;
    let index = 0;
    const auto = () => {
      autoTimer = setInterval(() => {
        show(index);
        index < numList.length - 1 ? index++ : index = 0;
      }, 2000);
    }
    auto();
    

    进阶3:还需要添加上鼠标移动前后的东西

      oImage.onmouseover = function() {
        if (autoTimer) clearInterval(autoTimer);
      }
      oImage.onmouseout = function() {
        auto();
      }
    

    进阶4:细节优化:关于我们若是我们刚好按到当前显示的轮播页,这个时间问题,就跟下面一起写了~

    进阶5:最后就是将代码模式变为面向对象的模式,使得同一页面上的多个轮播结构能够一起进行。这里的改动比较大,就直接上代码了。

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <style type="text/css">
        * {
          margin: 0;
          padding: 0;
        }
        ul, li {
          list-style: none;
        }
        body {
          background-color: #000;
        }
        .wrap {
          position: relative;
          border: 8px solid #fff;
          margin: 100px auto;
           400px;
          height: 250px;
          overflow: hidden;
        }
        .pic-group {
          position: absolute;
        }
        .pic-group li img {
          display: block;
           100%;
          height: 100%;
        }
        .num-group {
          position: absolute;
          bottom: 5px;
          right: 0;
          height: 20px;
        }
        .num-group li {
          float: left;
           20px;
          height: 20px;
          line-height: 20px;
          font-size: 10px;
          margin-right: 10px;
          background-color: #089e8a;
          color: #eee;
          text-align: center;
          border-radius: 10px;
          cursor: pointer;
          opacity: 0.8;
        }
        .num-group li:hover {
          box-shadow: 0 0 18px #000;
        }
        .num-group li.current {
          opacity: 1;
          color: #089a8a;
          background-color: #000;
        }
      </style>
    </head>
    <body>
      <div class="wrap">
        <ul class="pic-group">
          <li><img src="./pic1.jpg" alt=""></li>
          <li><img src="./pic2.jpg" alt=""></li>
          <li><img src="./pic3.jpg" alt=""></li>
          <li><img src="./pic4.jpg" alt=""></li>
          <li><img src="./pic5.jpg" alt=""></li>
        </ul>
        <ol class="num-group">
          <li class="current">1</li>
          <li>2</li>
          <li>3</li>
          <li>4</li>
          <li>5</li>
        </ol>
      </div>
    </body>
    <script type="text/javascript">
    var Carousel = function(cname) {
      this.init(cname);
    }
    Carousel.prototype = {
      init: function(cname) {
        let me = this;
        me.oWrap = document.getElementsByClassName(cname)[0];
        me.oImage = me.oWrap.getElementsByTagName("ul")[0];
        me.imageList = me.oImage.getElementsByTagName("li");
        me.imageHeight = me.imageList[0].offsetHeight;
        me.oNumber = me.oWrap.getElementsByTagName("ol")[0];
        me.numberList = me.oNumber.getElementsByTagName("li");
        me.index = 0;
        me.moveTimer = null;
        me.autoTimer = null;
        for (let i = 0; i < me.numberList.length; i++) {
          me.numberList[i].onmouseover = function() {
            me.index = i;
            me.Show(i);
          }
        }
        me.Auto();
        me.oImage.onmouseover = function() {
          clearInterval(me.autoTimer);
        }
        me.oImage.onmouseout = function() {
          me.Auto();
        }
      },
      Show: function(index) {
        let me = this;
        me.clearClass(index);
        me.Move(index);
      },
      Move(index) {
        let me = this;
        let target = -index * me.imageHeight;
        let now;
        let speed;
        if (me.moveTimer) clearInterval(me.moveTimer);
        me.moveTimer = setInterval(() => {
          now = me.oImage.offsetTop;
          speed = (target - now) / 10;
          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
          now === target ? clearInterval(me.moveTimer) : me.oImage.style.top = now + speed + "px";
        }, 20);
      },
      Auto() {
        let me = this;
        me.autoTimer = setInterval(() => {
          me.index < me.imageList.length - 1 ? me.index++ : me.index = 0;
          me.Show(me.index);
        }, 2000);
      },
      clearClass(index) {
        let me = this;
        for (let i = 0; i < me.numberList.length; i++) {
          me.numberList[i].className = "";
        }
        me.numberList[index].className = "current";
      }
    }
    window.onload = function() {
      new Carousel("wrap");
    }
    </script>
    </html>
    
  • 相关阅读:
    上学路线 (Standard IO)
    舞台设置 (Standard IO)
    Circle (Standard IO)
    Number (Standard IO)
    Gift (Standard IO)
    圆周舞蹈 (Standard IO)
    竞赛排名 (Standard IO)
    奶牛排队 (Standard IO)
    奶牛晒衣服 (Standard IO)
    神奇的风 (Standard IO)
  • 原文地址:https://www.cnblogs.com/can-i-do/p/8470819.html
Copyright © 2020-2023  润新知