zoukankan      html  css  js  c++  java
  • 原生js封装轮播图

    此文转载自:https://blog.csdn.net/yh604005215/article/details/111772471#commentBox

    工作原因,好久没更新博客了,今天来个用原生js写轮播图, 上代码

    class Banner {
      constructor(props = {}) {
        if (!(props?.root instanceof HTMLElement)) {
          throw "root是必选dom节点";
        }
        // 状态
        this.state = {};
        // 参数
        this.props = {
          type: "move",
          height: 600,
          width: 1000,
          imgs: [],
          ...props,
        };
        if (props.type === "move") {
          this.imgIndex = props.startIndex ? props.startIndex + 1 : 1;
        } else {
          this.imgIndex = props.startIndex || 0;
        }
        this.autoTimer; //自动轮播计时器
        this.animateTimer; //动画计时器
        this.init();
      }
    
      // 修改状态
      setState = (state = {}) => {
        this.state = {
          ...this.state,
          ...state,
        };
      };
    
      // 初始化
      init = () => {
        this.render();
        this.animate();
        this.autoMove();
        this.onChange();
      };
      // 渲染轮播图
      render = () => {
        const {
          root,
          height,
          width,
          type,
          imgs = [],
          showButton = true,
          showCheck = true,
        } = this.props;
        setStyle(root, {
          height,
          width,
          position: "relative",
        });
        root.className += " banner";
        const box = document.createElement("div");
        const imgBox = document.createElement("ul");
        const iconBox = document.createElement("ul");
    
        imgs.forEach((item) => {
          this.setImgNode(imgBox, item);
          const icon = document.createElement("li");
          iconBox.appendChild(icon);
        });
        // 滚动需要前后各插入图片
        if (type === "move") {
          this.setImgNode(imgBox, imgs[0]);
          this.setImgNode(imgBox, imgBox.children[0], imgs[imgs.length - 1]);
        } else {
          setStyle(imgBox.children[this.imgIndex], {
            zIndex: 90,
            opacity: 1,
          });
        }
    
        setStyle(imgBox, {
          width: type === "move" ? (imgs.length + 2) * width : width,
          height,
        });
        addClass(
          box,
          type === "move" ? "banner-img-box-move" : "banner-img-box-transparency"
        );
        iconBox.className = "banner-icon-box";
    
        box.appendChild(imgBox);
        root.appendChild(box);
        showCheck && root.appendChild(iconBox);
        showButton && this.renderButton(root);
        this.setState({
          box,
          imgBox,
          iconBox,
        });
      };
    
      // 渲染按钮
      renderButton = (node) => {
        const rightBtn = document.createElement("button");
        const leftBtn = document.createElement("button");
        rightBtn.innerHTML = ">";
        leftBtn.innerHTML = "<";
        rightBtn.className = "btn banner-right-btn";
        leftBtn.className = "btn banner-left-btn";
    
        node.appendChild(rightBtn);
        node.appendChild(leftBtn);
        this.setState({
          rightBtn,
          leftBtn,
        });
      };
    
      // 设置图片函数
      setImgNode(node) {
        const { height, width, type } = this.props;
        const li = document.createElement("li");
        li.innerHTML = `<img class="banner-img" src="${
          arguments.length > 2 ? arguments[2] : arguments[1]
        }" />`;
        setStyle(li, {
          height,
          width,
          opacity: type === "move" ? null : 0,
        });
        node.insertBefore(li, arguments.length > 2 ? arguments[1] || null : null);
      }
    
      //自动轮播
      autoMove = () => {
        const { time = 3000 } = this.props;
        this.autoTimer = setInterval(() => {
          this.imgIndex++;
          this.animate();
        }, time);
      };
    
      //动画
      animate = () => {
        const { type } = this.props;
        const { iconBox } = this.state;
        //dom集合转数组
        Array.from(iconBox.children).forEach((node, index) => {
          if (node.className?.indexOf("active") > -1) {
            removeClassName(node, "active");
          }
          if (this.imgIndex === (type === "move" ? index + 1 : index)) {
            addClass(node, "active");
          }
        });
        if (type === "move") {
          this.move();
        } else {
          this.transparency();
        }
      };
      //滚动轮播
      move = () => {
        const { iconBox, box } = this.state;
        const { imgs, width } = this.props;
    
        // 下标等于图片长度时需要重置到第一个小圆点
        if (this.imgIndex === imgs.length + 1) {
          addClass(iconBox.children[0], "active");
        }
        // 图片超过长度拉回第二张图片
        if (this.imgIndex === imgs.length + 2) {
          this.imgIndex = 2;
          box.scrollLeft = width;
          addClass(iconBox.children[1], "active");
        }
    
        if (this.imgIndex === 0) {
          addClass(iconBox.children[imgs.length - 1], "active");
        }
    
        //下标小于0时返回最后二张图片的下标
        if (this.imgIndex < 0) {
          this.imgIndex = imgs.length - 1;
          box.scrollLeft = width * imgs.length;
          addClass(iconBox.children[imgs.length - 2], "active");
        }
        //滚动条移动
        this.scrollMove();
      };
    
      //淡入淡出
      transparency = () => {
        const { imgBox, iconBox } = this.state;
        const { imgs } = this.props;
        if (this.imgIndex === imgs.length) {
          //下标到最后一张图片时变回第一张图片
    
          this.imgIndex = 0;
          addClass(iconBox.children[0], "active");
        }
        if (this.imgIndex < 0) {
          
          this.imgIndex = imgs.length - 1;
          addClass(iconBox.children[imgs.length - 1], "active");
        }
        Array.from(imgBox.children).forEach((item, index) => {
          this.opacitySwitch(item, 0);
          item.style.zIndex = 0;
        })
        this.opacitySwitch(imgBox.children[this.imgIndex], 100);
        imgBox.children[this.imgIndex].style.zIndex = 90;
      };
    
      // 所有操作函数
      onChange = () => {
        const { iconBox } = this.state;
        const { root, type } = this.props;
        iconBox.onmouseover = (e) => {
          if (e.target.nodeName !== "LI") return;
          clearInterval(this.autoTimer);
          const index = [].indexOf.call(e.target.parentNode.children, e.target);
          this.imgIndex = type === "move" ? index + 1 : index;
          this.animate();
          this.autoMove(); //重新启动
        };
        root.onclick = (e) => {
          if (e.target.className?.indexOf("banner-right-btn") > -1) {
            clearInterval(this.autoTimer);
            this.imgIndex++;
            this.animate();
            this.autoMove();
          } else if (e.target.className?.indexOf("banner-left-btn") > -1) {
            clearInterval(this.autoTimer);
            this.imgIndex--;
            this.animate();
            this.autoMove();
          }
        };
      };
    
      //透明度切换
      opacitySwitch = (ele, target) => {
        let num = 10;
        clearInterval(this.animateTimer);
        this.animateTimer = setInterval(() => {
    
          let speed = target > num ? 5 : -5;
          //剩余可运动量 <= 每次所走的量
          if (Math.abs(target - num) <= Math.abs(speed)) {
            clearInterval(this.animateTimer); //结束运动
            ele.style.opacity = target / 100; //到达终点
          } else {
            num += speed;
            ele.style.opacity = num / 100;
          }
        }, 30);
      };
    
      //滚动条移动
      scrollMove() {
        const { box, imgBox } = this.state;
        const { width } = this.props;
        clearInterval(this.animateTimer); //清除计算器
        let minStep = 0; //起始步数
        let maxStep = 20; //最大步数
        let start = box.scrollLeft; //运动起始位置
        let end = this.imgIndex * width; //结束位置
        let everyStep = (end - start) / maxStep; //每一步的距离
        this.animateTimer = setInterval(() => {
          minStep++;
          if (minStep >= maxStep) {
            //判断到达最大步数
            clearInterval(this.animateTimer); //清除计算器
          }
          start += everyStep; //起始位置加上走的距离
          box.scrollLeft = start;
        }, 20);
      }
    }
    
    // 设置css
    function setStyle(root, style = {}) {
      Object.keys(style).forEach(
        (item) => (root.style[item] = getStyleValue(item, style[item]))
      );
    }
    // 特殊处理设置宽高样式 数字
    function getStyleValue(key = "", value) {
      const arr = ["height", "width", "top", "left", "right", "bottom", "border"];
      return arr.indexOf(key.toLowerCase()) > -1 &&
        value !== 0 &&
        value &&
        !isNaN(value)
        ? value + "px"
        : value;
    }
    // 增加类名
    function addClass(ele, value) {
      if (!ele.className) {
        ele.className = value;
      } else {
        newClassName = ele.className;
        newClassName += " ";
        newClassName += value;
        ele.className = newClassName;
      }
    }
    
    // 删除class函数
    function removeClassName(ele, className) {
      let str = ele.className,
        index = str.indexOf(className);
      if (index > -1) {
        ele.className = str.replace(className, "");
      }
    }
    
    

    css 部分写的稍微简陋一些

    * {
      margin: 0;
      padding: 0;
    }
    li {
      list-style: none;
    }
    .banner {
      position: relative;
    }
    .banner-img-box-move {
      overflow: hidden;
      height: 100%;
      width: 100%;
      position: relative;
    }
    .banner-img-box-move > ul > li > img {
      height: 100%;
      width: 100%;
    }
    .banner-img-box-move > ul > li {
      float: left;
    }
    .banner-icon-box {
      position: absolute;
      right: 20px;
      bottom: 20px;
      z-index: 99;
      display: flex;
    }
    .banner-icon-box > li {
      height: 15px;
      width: 15px;
      margin-right: 12px;
      background-color: #eee;
      border-radius: 50%;
    }
    .banner-img-box-transparency {
      position: relative;
    }
    .banner-img-box-transparency > ul > li {
      position: absolute;
      left: 0;
      top: 0;
    }
    .banner-img-box-transparency> ul > li >img{
      height: 100%;
      width: 100%;
    }
    .btn {
      position: absolute;
      height: 40px;
      width: 40px;
      z-index: 99;
    }
    .banner-left-btn {
      left: 0;
      top: 50%;
      transform: translateY(-50%);
    }
    .banner-right-btn {
      right: 0;
      top: 50%;
      transform: translateY(-50%);
    }
    .active {
      background-color: red !important;
    }
    

    使用

    
    <script>
    
    const imgs = ['images/1.jpg','images/2.jpg','images/3.jpg','images/4.jpg','images/5.jpg',]
    
    const root = document.querySelector('#root');
    new Banner({
        imgs,
        root,
        type: 'transparency', //move是滚动轮播, transparency是透明度
        width: 1000,
        height: 400,
    })
    </script>
    
       

    更多内容详见微信公众号:Python测试和开发

    Python测试和开发

  • 相关阅读:
    js 监听页面url锚点变化 window.onpopstate
    js 返回上一页并刷新页面
    table 会有默认的外边框,内部会有分割线
    javascript 中设置window.location.href跳转无效问题解决办法
    chrom控制台常用方法
    Acquire and Release Fences
    常用 git 命令
    vim版本更新
    vim bundle安装
    emacs 常用命令
  • 原文地址:https://www.cnblogs.com/phyger/p/14202532.html
Copyright © 2011-2022 走看看