原生JS带你手写高级无缝轮播图实战案例(超赞)

前言

        Javascript虽然在工作上用的很少,但是还是非常重要的。是一个不可跨越的一个阶段。因为很多东西都是基于原生JS实现的,包括vue的源码。所以工作中如果有时间的话,也可以和我一样撸撸原生JS。

简介

        这个轮播图涵盖很多javascript中的知识点以及使用方法,这里我就不文字说明代码逻辑了。直接上代码,里面会有注释,如果有不懂的欢迎评论,最近才开始写博客,有不好的地方多多见谅哈。

/*
    这里是初始化函数init(),我先介绍一下各个变量的作用:
           area,imgCon分别是显示区域,以及显示区域内部图片的区域
           ul是轮播图下方小圆点的盒子元素
           pos代表的是当前area中显示图片的下标
           direction 是图片移动的方向,当我们点击左边的按钮图片是往右边滑动的,类推..
           imgSrcList是每张图片的src数组列表,我们可以遍历创建img并放入
           imgList,btnList,cricleList分别是图片元素节点,左右按钮元素节点,和下方ul中小
           圆圈li的元素节点。我们先了解这些,剩余变量会在下文中解释。

*/

var area,imgCon,ul,pos = 0,bool = false ,x=0,prev ,time = 100 , autoBool = false;
const SPEED = 30 , LEFT = "left" , RIGHT = "right;
var direction = "";
var imgList = [];
var imgSrcList = 
['./img/a.png','./img/b.png','./img/c.png','./img/d.png','./img/e.png'];
var btnList = [], circleList = [];

        init();
        function init(){
            area = ce("div",{
                width:"1500px",
                height:"500px",
                position:"relative",
                background:"pink",
                overflow:"hidden",
                margin:"0 auto",
            })
             //创建图片区域(也可以叫滑动区域)
            createImgCon();
            //创建左右按钮节点并放入btnList中
            createBtn();
            //创建ul以及li节点并放入circleList节点列表中
            createCircle();
            //自动轮播的函数
            setInterval(interHandler,16);
            //初始化当前原点样式
            prevHandler();
            document.body.appendChild(area);
        }

初始化基本样式

        这里先介绍一下ce是一个什么东西,这个一个自己封装的一个简易的创建标签以及样式的函数,这个函数还是有很多不足的,很多东西没有判断,但是这个东西只是我们自己使用的话还是比较方便的。

//快速创建标签样式
        //需要传入一个string类型和一个对象
       function ce(type,style){
            var elem = document.createElement(type);
            Object.assign(elem.style,style);
            return elem;
        }
        //创建图片区域
        function createImgCon(parent){
            imgCon = ce("div",{
                width:"3000px",
                height:"500px",
                position:"absolute",
                left:"0",
                background:"#ccc"
            })
            for(let i=0;i<imgSrcList.length;i++){
                var img = ce("img",{
                    width:"1500px",
                    height:"500px"
                })
                //这里放的就每个img图片的元素节点
                imgList.push(img);
                img.src = imgSrcList[i];
            }
            //将下标为0的图片放入滑动区域中,默认显示第一张图片
            imgCon.appendChild(imgList[0])
            area.appendChild(imgCon);
        }
        //创建左右按钮
        function createBtn(parent){
            var arr = ['left',"right"]
            for(let i=0;i<arr.length;i++){
                var btn = ce("div",{
                    width:"30px",
                    height:"60px",
                    position:"absolute",
                    background:`#000 url('./img/${arr[i]}.png')`,
                    opacity:"0.3",
                    left:`${arr[i] === 'left' ? "30px" : ""}`,
                    right:`${arr[i] === 'right' ? "30px" : ""}`,
                    top:"50%",
                    transform:"translateY(-50%)"
                })
                //btnList放的就是每次创建好的div节点元素,所对应的是左右按钮
                btnList.push(btn);
                btn.addEventListener("click",btnClickHandler);
                //将每次的左右按钮放入显示区域中
                area.appendChild(btn);
            }
        }
        //创建圆圈图标
        function createCircle(){
            // 这里就是创建一个ul标签以及它的样式是后面的这个对象
            ul = ce("ul",{
                width:"260px",
                height:"40px",
                position:"absolute",
                bottom:"30px",
                left:"50%",
                transform:"translateX(-50%)",
                display:"flex",
                justifyContent:"space-evenly"
            })
            //创建li放入ul
            for(let i=0;i<imgSrcList.length;i++){
                var li = ce("li",{
                    width:"36px",
                    height:"36px",
                    borderRadius:"100%",
                    listStyle:"none",
                    border:"2px solid red"
                })
                ul.appendChild(li);
                //btnList放的就是每次创建好的div节点元素,所对应的是左右按钮
                circleList.push(li);
            }
            ul.addEventListener("click",circleHandler)
            //将ul放入显示区域中
            area.appendChild(ul);
        }

功能部分

        当我们初始化基本样式以后,开始写功能了,前面也对大部分的变量进行了一个解释,接下来看当点击左右按钮和下方小圆圈图标的时候所对应的事件处理函数。

        /*---左右按钮点击处理函数
                1.主要确定图片移动方向
                2.点击修改当前图片索引pos
        */
        function btnClickHandler(e){
            if(bool)return;
            if(e.target.style.backgroundImage.includes("left")){
                pos--;
                if(pos<0) pos=imgSrcList.length-1;
                direction = RIGHT;
            }else if(e.target.style.backgroundImage.includes("right")){
                pos++;
                if(pos>imgSrcList.length-1)pos=0;
                direction = LEFT;
            }
            createImage();
        }

        /*---下面ul圈圈点击事件处理函数
                1.确定当前pos的值
                2.确定图片的移动方向
                3.确定完毕后创建对应方向的图片
        */
       function circleHandler(e){
        if(bool)return;
        //给ul绑定的事件,这里使用到了事件委托机制,直接判断目标对象的节点名
        if(e.target.nodeName != "LI")return;
        //获取当前点击小圆圈所在circleList数组中的下标
        var index = circleList.indexOf(e.target);
        /*
            判断当前点击index的以及当前显示的pos
                1.当pos ==index 时候说明点击的是同一个圆圈
                2.当大于或者小于的时候我们都修改全局变量pos
                3.通过判断两个值的大小确定图片的移动方向,这里不要弄混淆了!
        */
        if(index == pos) return;
        if(index>pos){
            pos = index;
            direction = LEFT;
        }else if(index < pos){
            pos = index;
            direction = RIGHT;
        }
        //
        createImage();
       }

          现在我们确定了方向了,那就可以知道图片是放在那里了,现在执行createImg这个函数。

       /*---处理函数通过判断图片移动方向将对应的pos图片放入*/
     function createImage(){
      if(direction == RIGHT){//点击了左边边的按钮,或者点击的圆圈index>pos,图片向右移动
          imgCon.insertBefore(imgList[pos],imgCon.firstElementChild);
            //这里还不能让图片动起来,所以显示区域应该还是显示imgList[0]这个节点中的img
          imgCon.style.left = "-1500px";
            //所以x就是表示left的初始值,存起来,后面图片移动的时候从x开始移动
          x = -1500;
        //点击了右边的按钮或者点击的圆圈index<pos,图片向左移动
      }else if(direction == LEFT){
          //这里也是的记录了left的初始值。
          x=0;
            //将将要显示的图片放入滑动区域最后面
          imgCon.appendChild(imgList[pos]);
      }
        //这里是控制定时器开启与进入的
      bool = true;
        //刷新当前的原点样式函数
      prevHandler();
     }

  图片移动

        现在基本准备都做好了,确定了要显示的图片下标pos,图片节点数组imgList,图片移动方向,以及图片已经在对应位置放好了,不多说了,解释都在代码中....

       // 函数初始化开始时定时器开启
       function interHandler(){
            moveImgae();
            autoPlay();
       }
       function moveImgae(){
        //什么时候停呢??
       //当点击左右按钮或者ul里面的小圆圈的时,图片滑动完毕,定时器就要关闭了。
            if(!bool)return;
            if(direction == RIGHT){
                //SPEED是一个数值常量,其表示的是图片移动的速度
                //我们这里是每16毫秒移动30px
                x +=SPEED;
             /*
               当图片移动完成时候:
                 1.删除之前的图片以便后面点击的图片没地方放,因为图片只能容纳两张图片
                 2.将x清0,因为删除以后滑动区域只有一张图片了,且x=0的时候才能显示
                 3.暂时停止定时器,不让其运行
             */
                if(x >= 0){
                    imgCon.lastElementChild.remove();
                    x=0;
                    bool=false;
                };
                imgCon.style.left = `${x}px`
            }
            if(direction == LEFT){
        //这里和上面一样的道理,x初始值为0,需要让后面的图片显示所以x需要为负数
                x -= SPEED;
                if(x <= -1500){
                    imgCon.firstElementChild.remove();
                    x=0;
                    bool=false;
                };
                imgCon.style.left = `${x}px`;
            }
       }

小结分析   

        所以这里可以串通起来了,程序开始的时候定时器是关闭的,当点击左右按钮和小圆圈之后都会开启定时器,当图片移动完成之前点击左右按钮和小圆圈都会不进入函数,图片完成移动后删除完成后暂停定时器之后才可以点击左右按钮和小圆圈。

成功一步之遥

        最后就是让其自动轮播啦,这里采用的是事件抛发,看—————————>代码。

        //对显示区域进行移入移出事件侦听
        area.addEventListener("mouseenter",mouseHandler);
        area.addEventListener("mouseout",mouseHandler);
        function mouseHandler(e){
            /*
             e为事件目标对象,e.type为目标对象事件类型
                当事件类型为鼠标移入时:
                    - 不让程序自动轮播,也就是autoPlay函数进不去。
                    - 之前没移入时所进行aotoPlay函数中的的time--需要重置
                当事件类型为鼠标移出时:    
                    - 程序开始进行自动轮播倒计时
            */
            if(e.type == 'mouseenter'){
                autoBool = true;
                time=100;
            }else if(e.type == "mouseout"){
                autoBool = false;
            }
        }

function autoPlay(){
        //要说bool是控制定时器中第一个函数的
        //autoplay就是是控制定时器中第二个函数的
        if(autoBool)return;
        //time代表的是等待定时器执行多少次后自动轮播,我们这里是100x16,1.6s
        time--;
        if(time<=0){
            //到时间了就会将我们创建的点击事件抛发给右边的按钮,默认点击
            //并且重置下一张图片移动所等待的时间。
            time=100;
            var event = new MouseEvent("click");
            btnList[1].dispatchEvent(event)
        }
       }

        继续看————————>代码

    /*
        这个函数是一个刷新当前显示图片pos值后所对应ul中li小圆圈的样式进行刷新操作。
        prev代表的是上一个显示的节点元素,默认是没有对prev的,初始化的时候pos=0就会将
        第0个赋值给prev。至此一以后每一次点击左右按钮或者小圆圈的时候都需要刷新当前
        下标pos所对应的样式
    */   
    function prevHandler(){
        if(prev){
            prev.style.backgroundColor = "rgba(255,0,0,0)";
        }
            prev = circleList[pos];
            prev.style.backgroundColor = "rgba(255,0,0,0.6)";
       }

              完结......撒花撒花 需要源码的可以私信我

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值