🚛JS手写一个轮播图🚛

2,522 阅读6分钟

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!\

前言

📞📞大家好我是 木瓜轮播图很多场景都能应用的到,网站的广告、电商的宣传图等等。平常都用插件一把撸。今天突然对轮播图的实现原理感兴趣,尝试用js手写一个轮播图,帮助巩固加深下js的运用。

代码效果

📢📢顺便说一下,蒜必秒吻😡😡

基本功能

  • 自动切换轮播图
  • 点击左右箭头切换轮播图
  • 点击下方圆点切换轮播图

整体结构与实现

  • HTML结构

image.png 这里的HTML大体分为四部分

  • 最外层的盒子banner作为主体
  • 两个arrow a标签作为箭头
  • ul轮播图
  • 以及ol小圆点
<div class="banner">
        /*左右箭头 这里用两个a标签显示,同时限制a标签的默认跳转*/
        <a href="javascript:;" class="arrow-l">&lt;</a>
        <a href="javascript:;" class="arrow-r">&gt;</a>
        /* 轮播图主体*/
        <ul class="slider">
            <li>
                <a href="#"><img    src="https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF" alt=""></a>
            </li>
            <li>
                <a href="#"><img src="https://t7.baidu.com/it/u=737555197,308540855&fm=193&f=GIF" alt=""></a>
            </li>
            <li>
                 <a href="#"><img src="https://t7.baidu.com/it/u=1297102096,3476971300&fm=193&f=GIF" alt=""></a>
            </li>
            <li>
                 <a href="#"><img src="https://t7.baidu.com/it/u=12235476,3874255656&fm=193&f=GIF" alt=""></a>
            </li>
            <li>
                 <a href="#"><img src="https://t7.baidu.com/it/u=1700588201,792130339&fm=193&f=GIF" alt=""></a>
            </li>
         </ul>
         /*轮播图下方小圆点*/
        <ol class="cirbox">

        </ol>
        <input type="text" value="几页"><button>确定</button>
    </div>
  • CSS部分
  1. banner盒子作为展示主体,设置overflow: hidden
  2. ul设置6倍于banner的宽度,同时使li float存放banner图
  3. 左右箭头用a标签
  * {
            margin: 0;
            padding: 0;
        }

        .banner {
            margin: 100px auto;
            position: relative;
            width: 720px;
            height: 455px;
            /*border: 1px solid #eee;*/
            overflow: hidden;
        }

        .banner ul {
            position: absolute;
            
            height: 455px;
            width: 600%;
            left: 0;
            top: 0;
        }

        .focus ul li {
            height: 455px;
            width: 720px;
            list-style: none;
            float: left;
            color: white;
        }

        .banner ul li img {
            width: 100%;
            height: 100%;
        }

        .banner .arrow-l,
        .banner .arrow-r {
            display: none;
            width: 24px;
            height: 40px;
            position: absolute;
            opacity: .5;
            top: 50%;
            z-index: 2;
            background-color: gray;
            text-align: center;
            line-height: 40px;
            font-size: 25px;
            color: white;
            text-decoration: none;
        }

        .banner .arrow-r {
            right: 0px;
        }

        .cirbox {
            position: absolute;
            bottom: 10px;
            width: 100%;
            text-align: center;
            height: 15px;
            display: inline-block;
            height: 15px;
            width: 100%;
            /*background: rgba(100, 100, 100, 0.5);*/
            border-radius: 7px;
            font-size: 0;
            /*不加这一句,会使li在ul中向下偏移*/
        }

        .cirbox li {
            display: inline-block;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background: #fff;
            cursor: pointer;
            margin: 10px;
        }

        .cirbox .active {
            background: red;
        }

需要注意的事项

  • 图片的宽,高度要和slider中的li标签, 以及div.banner的宽,高度一致。

  • img的宽度为(图片数目+1)*每张图片的宽度。

  • div .banner部分使用overflow:hidden隐藏slider超出的部分,确保每次该区域只能显示一张图片。

  • css部分主要弄明白轮播图的实现是通过设置ul的left值以及div盒子的overflow:hidden来控制轮播的展示,这里不再赘述。

JS部分(功能实现)

左右按钮切换轮播图

是通过控制ul的left值来实现显示某张图片,但是不能直接改变left值,需要逐渐改变left来实现切换效果。这里我们定义一个动画函数animate来逐渐改变ul的left值,实现切换的动画效果。

 function animate(obj, target, callback) { //参数为对象和预期目标
    clearInterval(obj.timer);
    obj.timer = setInterval(function() { //为不同的对象定时器赋予不同的名字
        var step = (target - obj.offsetLeft) / 10;
        step = step > 0 ? Math.ceil(step) : Math.floor(step); //注意写在里面
        if (obj.offsetLeft == target) { //清除动画,原理是如果盒子的左边距大于target,清除定时器
            clearInterval(obj.timer);
            if (callback) {
                callback();
            }
        }
        obj.style.left = obj.offsetLeft + step + 'px'; //利用定时器的原理使盒子向右移动,
    }, 15);

}

左右按钮的click事件,这里左右箭头展示与否是通过控制鼠标是否经过focus盒子

 var focus = document.querySelector('.focus');       //banner轮播图展示主体
        var arrow_l = document.querySelector('.arrow-l');   //banner轮播图左箭头
        var arrow_r = document.querySelector('.arrow-r');   //banner轮播图右箭头

        //鼠标经过显示左右按钮,关闭定时器
        focus.addEventListener('mouseenter', function () {
            arrow_l.style.display = 'block';
            arrow_r.style.display = 'block';
            clearInterval(timer);


        });

        //离开隐藏按钮,开启定时器
            focus.addEventListener('mouseleave', function () {
                arrow_l.style.display = 'none';
                arrow_r.style.display = 'none';
                timer = setInterval(function () {

                    arrow_r.click(); //手动调用右边按钮点击事件
                }, 2000);

            })

当图片从最后一张切换回到第一张时,这时就不能通过改变ulleft值来实现滚动的效果,于是克隆第一张图片至列表尾部,当展示完最后一张图片时,继续滚动到克隆的第一张,然后将ulleft值置为0。 这时候展示的极快,会让人在无缝滚动。实际上是克隆第一个节点滚动,然后迅速把ul的left =0来继续滚动。

           if (num == ul.children.length - 1) { //指示器,当num == ul.children.length - 1,此时走到了clone
                ul.style.left = 0; //重新回到第一张图片,计数器重新开始
                num = 0;
            }

🎪🎪下面是完整的箭头click的事件代码(左右箭头代码同理,不同的是需要改变的left值)

         //无缝滚动,深克隆ul里第一个li,在for外,不会增加小圆点的长度
        var firstImg = ul.children[0].cloneNode(true);
        ul.appendChild(firstImg);
        var num = 0; //right按钮计算移动距离的索引
        var circle = 0; //小圆点计数器
        // console.log(ul.children.length - 1);

        //右边按钮的功能
        arrow_r.addEventListener('click', function () {
            if (num == ul.children.length - 1) { //指示器,当num == ul.children.length - 1,此时走到了clone
                ul.style.left = 0; //重新回到第一张图片,计数器重新开始
                num = 0;
            }
            num++;
            circle++;
            for (var i = 0; i < ol.children.length; i++) { //排他
                ol.children[i].className = '';
            }
            if (circle == ol.children.length) { //走到clone 复原成第一个
                circle = 0;
            }
            //console.log(circle);
            ol.children[circle].className = 'active';

            animate(ul, -num * focus.offsetWidth);
        });

        //左边按钮的功能
        arrow_l.addEventListener('click', function () {
            if (num == 0) {

                num = ul.children.length - 1; //
                ul.style.left = -num * focus.offsetWidth + 'px';
            }
            num--;
            circle--;
            for (var i = 0; i < ol.children.length; i++) { //排他,可以封装成一个函数
                ol.children[i].className = '';
            }

            if (circle < 0) {
                circle = ol.children.length - 1; //当circle小于0的时候,快速跳到最后一张图

            }
            ol.children[circle].className = 'active';
            animate(ul, -num * focus.offsetWidth);
        });

自动滚动的实现

🏡原理就是开启一个定时器,调用右边箭头的click事件来实现滚动。
🏡当鼠标移动到展示主体,关闭定时器,显示按钮。
🏡当鼠标移出取展示主体,开启定时器,隐藏按钮。

//自动播放图片
        var timer = setInterval(function () {

            arrow_r.click(); //手动调用右边按钮点击事件
        }, 2000);

动态添加小圆点

🚛根据图片li的个数动态创建小圆点,同时根据索引动态为小圆点添加active的css类,实现小圆点与图片的同步。

 var ul = document.querySelector('ul');
        //console.log(ul.children.length);
        var ol = document.querySelector('.cirbox');

        //动态创建元素li(轮播图的小圆点)
        for (var i = 0; i < ul.children.length; i++) {

            var lis = document.createElement('li');
            lis.setAttribute('index', i); //设置自定义属性li的索引index
            ol.appendChild(lis); //添加到ol后
            ol.children[0].className = 'active';

          

        };

点击小圆点切换轮播图

🕵️‍♂️给每个小圆点绑定了click事件,同时使其它小圆点的css类置空。切换轮播图原理与左右箭头切换的一致,这里不再赘述。

  lis.addEventListener('click', function () {
                for (var i = 0; i < ol.children.length; i++) { //ol li 排他思想

                    ol.children[i].className = '';
                }

                var index = this.getAttribute('index');
                num = index;
                circle = index;
                this.className = 'active';
                 var target = -index * focus.offsetWidth; //点击轮播图的下面的li 向左移动的距离 = index * focus 的距离
                animate(ul, target);s
            });

最后

🎉🎉好了,到这里一个简易轮播图已经搭建完成。大致原理也已经叙述。技术不精,如果其中有错误希望各位大佬指教。

推荐的轮播图插件

🎃轮播图嘛,还是直接使用插件来的快。这里给大家推荐一个好用的插件