从零到一学JS:写个原生轮播图

136 阅读3分钟

每日一kun:你连世界都没观过,哪来的世界观?

怎么说呢,用JS写原生轮播图,代码有点小多,所有加起来大概200行代码,不过该有的东西都有,自动播放,鼠标悬停停止播放,鼠标离开继续播放,还加了个节流阀,防止快速点击上下一页,轮播速度过快。

核心算法:juejin.cn/post/717661…
JS代码
    var span = document.querySelectorAll("span")
    var div = document.querySelector("div")
    var ulRotation = document.querySelector(".rotation")
    var ulFlooterLi = document.querySelector(".flooterLi")
    var away = ulRotation.children[0].offsetWidth
    var num = 0
    var liEnd = ulRotation.children[0].cloneNode(true)
    var flag = true
    for (var i = 0; i < ulRotation.children.length; i++) {
        var li = document.createElement("li")
        ulFlooterLi.appendChild(li)
        li.setAttribute("index", i)
        li.addEventListener("click", function () {
            for (var i = 0; i < ulFlooterLi.children.length; i++) {
                ulFlooterLi.children[i].className = ""
                this.className = "current"
                packageTimer(ulRotation, -away * (num = this.getAttribute("index")))
            }
        })
    }
    ulFlooterLi.children[0].className = "current"

    div.addEventListener("mouseenter", function () {
        span[0].style.display = "block"
        span[1].style.display = "block"
        clearInterval(rotationTimer)
    })
    div.addEventListener("mouseleave", function () {
        span[0].style.display = "none"
        span[1].style.display = "none"
        rotationTimer = setInterval(function () {
            span[1].click()
        }, 1500)
    })
    ulRotation.appendChild(liEnd)
    span[1].addEventListener("click", function () {
        if (flag) {
            flag = false
            if (num == ulRotation.children.length - 1) {
                num = 0
                ulRotation.style.left = "0px"
            }

            num++
            packageTimer(ulRotation, -num * away, function () {
                flag = true
            })
            for (var i = 0; i < ulRotation.children.length - 1; i++) {
                ulFlooterLi.children[i].className = ""
            }
            num == ulRotation.children.length - 1 ? ulFlooterLi.children[0].className = "current" : ulFlooterLi.children[num].className = "current"

        }
    })
    span[0].addEventListener("click", function () {
        if (flag) {
            flag = false
            num--
            if (num < 0) {
                num = ulRotation.children.length - 2
                ulRotation.style.left = -(num + 1) * away + "px"
            }

            packageTimer(ulRotation, -num * away, function () {
                flag = true
            })

            for (var i = 0; i < ulRotation.children.length - 1; i++) {
                ulFlooterLi.children[i].className = ""
            }
            ulFlooterLi.children[num].className = "current"

        }
    })

    var rotationTimer = setInterval(function () {
        span[1].click()
    }, 1500)
    var packageTimer = function (obj, away, comeBack) {
        clearInterval(obj.timer)
        obj.timer = setInterval(function () {
            var step = (away - obj.offsetLeft) / 10
            step = step > 0 ? Math.ceil(step) : Math.floor(step)
            if (obj.offsetLeft == away) {
                clearInterval(obj.timer)
                comeBack && comeBack()
            }
            obj.style.left = obj.offsetLeft + step + "px"
        }, 20)
    }

HTML代码
    <div>
        <span class="left">👈</span>
        <span class="right">👉</span>
        <ul class="rotation">
            <li><img src="./image/summer01.jpg"></li>
            <li><img src="./image/summer02.jpg"></li>
            <li><img src="./image/summer03.jpg"></li>
            <li><img src="./image/summer04.jpg"></li>


        </ul>
        <ul class="flooterLi">

        </ul>
    </div>
CSSS代码
    html {
        height: 100%;
    }

    body {
        height: 100%;
    }

    .left {
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
    }

    .right {
        position: absolute;
        right: 0;
        top: 50%;
        transform: translateY(-50%);
    }

    div {
        width: 720px;
        height: 500px;
        position: relative;
        left: 50%;
        top: 50%;
        transform: translate(-50%, -50%);
        overflow: hidden;
    }

    ul li img {
        width: 720px;
        height: 500px;
    }

    .flooterLi {
        width: 200px;
        position: absolute;
        bottom: 0px;
        left: 50%;
        transform: translateX(-50%);
    }

    .flooterLi li {
        float: left;
        width: 30px;
        list-style-type: disc;
    }

    .rotation {
        list-style: none;
        width: 500%;
        padding: 0;
        float: left;
        position: relative;
        left: 0px;
        z-index: -10;

    }

    .rotation li {
        float: left;

    }

    span {
        display: none;
        font-size: 25px;
    }

    .current {
        color: yellowgreen;
        width: 30px;
    }

效果图

2022-12-13-21-41-24.gif

说下几个关键的地方,span[1]这里的span[0]里面的0代表👈,1代表👉,整个轮播图所有元素全部使用百分比定位,这样可以使轮播图永远在屏幕中间,左右箭头永远在上下居中,下面的四个小点,也是靠底居中在轮播图

span[1].addEventListener里面绑定的点击事件所实现的函数写了两个不同的函数,关键点就是点击进来是先Num++,再去完成临界点后面的动作,还是先完成临界点后面的动作,再去Num--,上一页是写完成第一页到最后一页的切换,再实现Num--,调用算法完成换页,下一页反之。

        for (var i = 0; i < ulRotation.children.length - 1; i++) {
            ulFlooterLi.children[i].className = ""
        }
        ulFlooterLi.children[num].className = "current"     

上面的代码主要实现4个黑色小点的绿色高亮效果,如果代码看不懂,可以把里面Num单独提取出来var 一个新的变量放进去,因为我这里是直接使用上下一页切换的变量,所以如果你不提取出来那你必须看懂上下页是怎么切换的,再把变量套用到这里。

    li.addEventListener("click", function () {
        for (var i = 0; i < ulFlooterLi.children.length; i++) {
            ulFlooterLi.children[i].className = ""
            this.className = "current"
            packageTimer(ulRotation, -away * (num = this.getAttribute("index")))
        }
    })

这里主要就给Li绑定个点击事件,使用排他思想完成高亮显示,其他代码还好,num = this.getAttribute("index"),就这个有点难度,这里主要是要和翻页代码与小点高亮显示代码一起看,主要就是点击这个小点,把Li上自己定义的一个属性index里面的值取出来,再绑定给Num,这样你点击某个点的时候,代码就知道该显示那张图片与那个点应该高亮显示。

还有个节流阀,节流阀应该是最简单的,就加个IF判断,当翻页代码执行时,开启节流阀,这样在翻页代码执行完毕前,不管点多少次按钮,也不会执行翻页,翻页代码执行完后,使用轮播图核心算法里面的回调函数关闭节流阀,这样就可以继续点击按钮完成翻页。

Tips:Code never lies。