轮播图(面向对象)

轮播图,效果如下
效果图

一、js文件

1.Utils类
export default class Utils{
 static ce(type,style,parent){
        var elem=document.createElement(type);
        if(style){
            for(var prop in style){
                elem.style[prop]=style[prop];
            }
        }
        if(typeof parent==="string") parent=document.querySelector(parent);
        if(parent) parent.appendChild(elem);
        return elem;
    }}
2.LoadImage类
//声明LoadImage类继承EventTarget超类
export default class LoadImage extends EventTarget{
    list;  //预缓存的图片数组
    num=0;  //初始为0,每缓存一张照片,num++,用于遍历list内所有图片
    finishArr=[];  //将预缓存图片潜复制后加入到finishArr
    callBack;  //调用时以参数形式传入的函数,可以对全部加载完成后的finishiArr进行操作。
    static IMAGE_FINISH="imgFinish";  //为抛发事件设置常量事件名
    
    //构造函数(list: 存放图片src的数组,basePath:图片路径的相同部分;expandedName:图片的后缀名,执行最后返回finishArr数组的函数)
    constructor(list,basePath,expandedName,_callBack){  
        
        //继承超类EventTarget内容
        super();

        //判断第二个参数是不是函数,
        if(basePath.constructor===Function)
        {

            //如果为函数,直接将参数内容赋给callBack
             this.callBack=basePath;

             //执行changeList函数,并把返回值赋予list
             this.list=this.changeList(list)
        }else{

            //如果不是函数,参数还是原来顺序,并且执行changeList函数
            this.callBack=_callBack;     
            this.list=this.changeList(list,basePath,expandedName)
        }
        //执行loadImage函数
        this.loadImage();
    }

    //changeList函数:将图片地址整合为整体的地址
    changeList(list,basePath,expandedName){

        //如果基础地址存在,然后判断基础地址有无/ ,然后把基础地址跟list的图片名整合,最终存入list李表里
        if(basePath){
            basePath=basePath.endsWith("/") ? basePath : basePath+"/";
            list=list.map(item=>basePath+item);
        }

        //如果后缀名存在
        if(expandedName){

            //遍历list,将list内的元素根据 . 分割
            list=list.map(item=>{
                var names=item.split(".")
                
                //如果list内元素包含后缀名,直接返还,如果不包含,将expandedName加在元素后部
                if(/jpg|png|jpeg|bmp|gif|webp/i.test(names[names.length-1])) return item;
                return item+(expandedName.includes(".") ? expandedName : "."+expandedName);
            })
        }
        //返还整合后的list
        return list;
    }
    //缓存图片函数
    loadImage(){
        //将img实例化
        var img=new Image();

        //设置监听事件,如果未加载完成,执行loadHandler函数
        this.loadFn=e=>this.loadHandler(e)
        img.addEventListener("load",this.loadFn);

        //加载图片路径,将图片缓存在浏览器里
        img.src=this.list[this.num];
    }
    loadHandler(e){
        //设置img为监听事件,即缓存的图片
        var img=e.currentTarget;

        //将图片浅复制,然后存入finishArr数组内
        this.finishArr.push(img.cloneNode(false));

        //通过num 遍历整个list数组,将图片所有路径依次加载一遍。即将所有图片都缓存到浏览器内,并且将所有图片浅复制后放入finishArr数组内。
        this.num++;
       
       //如果num超出数组长度,即所有图片都加载完成后,删除监听事件,监听函数置为null
        if(this.num>this.list.length-1){
            img.removeEventListener("load",this.loadFn);
            this.loadFn=null;

            //如果callBack参数存在,通过callBack函数对finishArr进行操作。
            if(this.callBack){
                this.callBack(this.finishArr);
            }
            // 如果不存在,设置事件抛发
            else{
                var evt=new Event(LoadImage.IMAGE_FINISH);
                evt.list=this.finishArr;
                this.dispatchEvent(evt);
            }
            return;
        }
        //给图片赋予新路径,进而将图片缓存到浏览器内。触发加载事件
        img.src=this.list[this.num];
    }
}
3.Carousel类
import LoadImage from "./LoadImage.js";
import Utils from "./Utils.js";
export default class Carousel {
  imgList; //轮播图图片放入ingList数组中
  w;
  h;
  bnlist; //存放左右点击按钮的图片
  list; //存放只含有轮播图图片的数组
  imageCon; //存放两张图片隐藏在轮播图后边,通过调整定位改变位置,进而实现轮播图
  parent; //父元素
  dot; //轮播图下部点击小圆点整体ul图
  dotList = []; //轮播图下部点击小圆点li存入数组
  pos = 0; //通过pos 记录当前为第几张图片
  direction = ""; //记录轮播图转换时图片移动方向
  bool = false; //控制图片是否转换,转换开关
  x = 0; //控制imageCon left的值
  speed = 0.5; // 控制imageCon移动速度
  autoBool = false; //图片自动轮播开关
  time = 200; //设置防抖 200次执行一次
  pre; //设置下部小圆点 背景颜色透明度
  static carouselList = []; //存放轮播图,可以设置多个轮播图,然后添加到数组内
  constructor(_imgList) {
    this.imgList = _imgList;

    //创建播放轮播图的div
    this.carousel = this.createCarousel();

    //预缓存图片,并且全部缓存完成后执行finishHandler函数,此时图片已经是一个图片元素了
    new LoadImage(_imgList, (list) => this.finishHandler(list));

    //将创建的轮播图放入静态数组内
    Carousel.carouselList.push(this);
  
  }

  //将元素放入给定的父元素内
  appendTo(parent) {
    if (parent.constructor === String) parent = document.querySelector(parent);
    parent.appendChild(this.carousel);
    this.parent = parent;
  }

  //图片全部预缓存结束后执行的函数
  finishHandler(_list) {
    //将预缓存后存放浅复制图片的数组删除后两位,即删除左右按钮两张图片,将删除的两张图片存入新数组内
    this.bnlist = _list.splice(-2);

    //如果w不存在,给w赋予轮播图第一张图片的宽和高
    if (!this.w) {
      this.w = _list[0].width / 100;
      this.h = _list[0].height / 100;
    }
    // 到此为止w和h正式全部确认完毕
    this.list = _list.map((item) => {
      item.style.width = this.w + "rem";
      item.style.height = this.h + "rem";
      return item;
    });

    //给carousel设置宽高
    Object.assign(this.carousel.style, {
      width: this.w + "rem",
      height: this.h + "rem",
    });

    //图片全部加载完成后执行以下函数
    this.createImageCon();
    this.createBn();
    this.createDot();
    this.changePre();
  }

  //setWH函数 :设置图片宽高
  setWH(_w, _h) {
    //如果图片加载完成,直接返回
    if (!this.parent) return;

    //如果传入的参数为布尔值
    if (_w.constructor === Boolean) {
      //如果第一个为true
      if (_w) {
        //则以父元素的宽作为图片的宽,高为宽的一半
        var rect = this.parent.getBoundingClientRect();
        this.w = rect.width / 100;
        this.h = this.w / 3;
      }
      //如果第一个参数为数值型,宽高为 传入的参数
    } else if (_w.constructor === Number) {
      this.w = _w / 100;
      this.h = _h / 100;
    }
  }

  //创建轮播图容器
  createCarousel() {
    var carousel = Utils.ce("div", {
      position: "relative",
      margin: "auto",
      overflow: "hidden",
      left: 0,
      right: 0,
      backgroundColor: "rgba(255,0,0,0.1)",
    });

    //为轮播图容器设置鼠标滑入和鼠标滑出事件,用来实现 轮播图自动播放
    carousel.addEventListener("mouseenter", (e) => this.mouseHandler(e));
    carousel.addEventListener("mouseleave", (e) => this.mouseHandler(e));
    return carousel;
  }

  //创建图片存放的div,存放两张图片,以实现图片实现
  createImageCon() {
    this.imageCon = Utils.ce("div", {
      width: this.w * 2 + "rem",
      height: this.h + "rem",
      position: "absolute",
      left: 0,
    });

    //将第一张图片放入图片存放容器中
    this.imageCon.appendChild(this.list[0]);
    //将图片存放容器放入轮播图div中
    this.carousel.appendChild(this.imageCon);
  }
  //创建左右按钮
  createBn() {
    //遍历存放左右按钮的数组,并且给图片元素添加CSS样式
    this.bnlist.forEach((item, index) => {
      Object.assign(item.style, {
        position: "absolute",
        left: index === 0 ? "20px" : "none",
        right: index === 1 ? "20px" : "none",
        top: (this.h - item.height / 100) / 2 + "rem",
      });

      //给左右按钮添加点击事件
      item.addEventListener("click",e => this.clickHandler(e));

      //将左右按钮添加到轮播图容器里
      this.carousel.appendChild(item);
    });
  }

  createDot() {
    //创建存放轮播图下方小按钮的ul
    this.dot = Utils.ce("ul", {
      listStyle: "none",
      margin: "0px",
      padding: "0px",
      position: "absolute",
      bottom: "0.2rem",
    });
    //根据存放图片数组的长度创建小按钮li
    this.list.forEach((item, index) => {
      var li = Utils.ce(
        "li",
        {
          width: "0.15rem",
          height: "0.15rem",
          backgroundColor: "rgba(255,0,0,0)",
          border: "1px solid #FF0000",
          borderRadius: "0.15rem",
          float: "left",
          marginLeft: index === 0 ? 0 : "0.1rem",
        },
        this.dot
      );

      //将创建的li放入dotList数组内
      this.dotList.push(li);
    });

    //将小按钮添加到轮播图容器内
    this.carousel.appendChild(this.dot);

    //给小按钮设置位置
    this.dot.style.left = (this.w - this.dot.offsetWidth / 100) / 2 + "rem";
    //给小按钮添加点击事件
    this.dot.addEventListener("click", (e) => this.clickDotHandler(e));
  }

  //左右按钮触发后执行的函数
  clickHandler(e) {
    if(this.bool) return;
    //如果侦听的元素为左右按钮数组内的第0为 即左按钮时
    if (this.bnlist.indexOf(e.currentTarget) === 0) {
      //pos-1,pos为轮播图图片的“编号”,图片依靠pos改变。
      this.pos--;
      //如果pos小于零说明左侧没有图片了,pos等于最右侧图片“编号”
      if (this.pos < 0) this.pos = this.list.length - 1;
      //图片此时向右滑动
      this.direction = "right";
    }
    //else即为右按钮
    else {
      //pos的值+1
      this.pos++;
      //如果pos大于了图片的个数,则右侧没有图片了,pos等于最左侧图片的“编号”,即0
      if (this.pos > this.list.length - 1) this.pos = 0;
      //此时pos向左移动
      this.direction = "left";
    }
    //然后执行图片切换函数
    this.createNextImage();
  }

  //点击下方小按钮执行的函数
  clickDotHandler(e) {
    if(this.bool) return;
    //委托事件,如果点击的元素不是li,直接返回
    if (e.target.constructor !== HTMLLIElement) return;

    //声明index为点击的li在数组内的下标
    var index = this.dotList.indexOf(e.target);

    //如果点击li的下标等于当前pos,即小按钮对应的图片一致时,直接返回
    if (index === this.pos) return;

    //根据下标和pos的大小判断点击li后图片应该左移还是右移
    this.direction = index > this.pos ? "left" : "right";

    //然后将pos改为点击li的下标
    this.pos = index;
    //执行更换图片的函数
    this.createNextImage();
  }
  //更换图片函数
  createNextImage() {
    //如果移动方向为左
    if (this.direction === "left") {
      //将在图片列表里下标为pos的图片元素插入到存放图片用来转换的容器内
      this.imageCon.appendChild(this.list[this.pos]);
      this.imageCon.style.left = "0rem";
      this.x = 0;
    }
    //如果移动方向为右
    else {
      //在转换容器的最左侧插入下标为pos的图片元素
      this.imageCon.insertBefore(this.list[this.pos], this.imageCon.firstChild);
      //然后将给转换容器定位为-w ,即把准备切换的图片切换到最左侧,以实现切换动画效果
      this.imageCon.style.left = -this.w + "rem";
      //x赋值为-w
      this.x = -this.w;
    }
    //将切换开关设置为true
    this.bool = true;
    //执行下方按钮背景图改变函数
    this.changePre();
  }

  changePre() {
    //如果pre存在,先把所有小圆点背景色设为透明
    if (this.pre) {
      this.pre.style.backgroundColor = "rgba(255,0,0,0)";
    }
    //然后给pre赋值为下标为pos的小圆点,并且将其背景色设置为0.6透明
    this.pre = this.dotList[this.pos];
    this.pre.style.backgroundColor = "rgba(255,0,0,0.6)";
  }

  //鼠标滑入滑出事件执行的函数
  mouseHandler(e) {
    //如果鼠标滑入,自动播放关闭,且防抖time设为200
    if (e.type === "mouseenter") {
      this.autoBool = false;
      this.time = 200;
    } else {
      //如果鼠标滑出,开始自动播放
      this.autoBool = true;
    }
  }
  //改变函数
  update() {
    this.imgMove();
    this.autoPlay();
  }

  //图片转换函数
  imgMove() {
    //判断容器是否移动,否的话直接返回
    if (!this.bool) return;

    //如果移动方向为左
    if (this.direction === "left") {
      
      //x值逐渐减少,即容器定位左移,显示图片左移效果
      this.x -= this.speed;
      //当x<=-w时,x=0,关闭转换开关,,并且删除第一张在转换容器的图片
      if (this.x <= -this.w) {
        this.x = 0;
        this.bool = false;
        this.imageCon.firstElementChild.remove();
      }
      //转换容器定位到x
      this.imageCon.style.left = this.x + "rem";
    } else {

        //右移时,x值从-w逐渐增大,即容器右移,图片右移效果
      this.x += this.speed;
      //当x>=0时,x=0,关闭转换开关,删除之前图片
      if (this.x >= 0) {
        this.x = 0;
        this.bool = false;
        this.imageCon.lastElementChild.remove();
      }

      //转换容器定位到x=0
      this.imageCon.style.left = this.x + "rem";
    }
  }
  //自动播放函数
  autoPlay() {
      //如果开关为关,即鼠标滑入,直接返回
    if (!this.autoBool) return;
    this.time--;

    //如果开关为开,即鼠标滑出,抛发给右按钮点击事件
    if (this.time > 0) return;
    this.time = 200;
    var evt = new MouseEvent("click");
    this.bnlist[1].dispatchEvent(evt);
  }

  //静态改变方法,可以给全部的轮播图实现改变
  static UPDATE() {
    for (var i = 0; i < Carousel.carouselList.length; i++) {
      Carousel.carouselList[i].update();
    }
  }
}

二、html代码

<!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>
        html
        {
            font-size: 100px;
        }
        body
        {
            font-size: 16px;
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
    <script type="module">
           import Carousel from "./js/Carousel.js";

           //设置浏览框改变事件
        window.addEventListener("resize",resizeHandler);
           animation();
           var arr=["./img/a.png","./img/b.png","./img/c.png","./img/d.png","./img/e.png","./img/left.png","./img/right.png"];
           var arr1=["./img/a.jpeg","./img/b.jpeg","./img/c.jpeg","./img/d.jpeg","./img/e.jpeg","./img/left.png","./img/right.png"];

           //实例化轮播图1对象
           let carousel=new Carousel(arr);
           //将轮播图添加到body里
           carousel.appendTo("body");
           //图片的宽高等于父元素容器的宽高
           carousel.setWH(true);

            //实例化轮播图2对象
           let carousel1=new Carousel(arr1);
           //将轮播图添加到body里
           carousel1.appendTo("body");
           //将图片大小设置为固定大小
           carousel1.setWH(600,200);
             
           //动画函数
           function animation(){
               requestAnimationFrame(animation);
               //所有轮播图都执行静态UPDATE函数
               Carousel.UPDATE();
           }
           //改变html内部元素大小,实现浏览框缩小放大时,轮播图跟着缩小放大
           function resizeHandler(e){
             document.documentElement.style.fontSize=document.documentElement.clientWidth*(100/screen.width)+"px";
           }
    </script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_45261642/article/details/107880258