基于原生Javascript的无缝轮播

一、前言

  • 轮播图的种类

说起轮播图,种类那可是五花八门,什么淡入淡出呀、旋转木马呀、3D轮播呀、无缝轮播呀等等,简直是秀的头皮发麻~
本文要讲的就是其中的无缝轮播,小伙伴们知道是怎么实现的吗,如果不知道的话,嘿嘿,你就接着往下看吧。如果你知道的话,就当捧个场,也往下看吧~

  • 基本要求

html和css完成静态布局、js获取并且操纵元素,定时器的应用,节流函数,日期对象等等。

二、无缝轮播的原理

首先,我们来看看什么是无缝轮播,就像下图所示:

其大概过程就是,上一张图片从左往右(或从右往左离开),下一张图片从左往右(或从右往左)进入。哎呀,貌似很简单的样子,有些小伙伴立马就想到了一个大容器里面有一个ul,ul里面有若干个li并且存放图片,把每个li的宽度设置成和容器同宽,然后每次点击的时候改变ul的left值就行了。嗯,很想很有道理的样子,于是三下五除二就做出来了,但是却发现有点问题,就像下面这样:
基于原生Javascript的无缝轮播_第1张图片
从第一张到倒数第二张图片还好,但是从最后一张图片到第一张图片就有问题了,并没有从最后一张图片直接切换到第一张图片,而是经过了中间的图片慢慢过渡到第一张图片(第一张图片到最后一张图片也同理),这显然不是预期的效果。问题既然已经发现了,就要去解决它,那么如何才能达到从最后一张图片直接切换到第一张图片(或第一张到最后一张),也就是无缝的效果,答案很简单,我们需要多一张图片(这张图片和第一张图片是相同的)放在图片列表的最后!为什么需要这样一张图片,请往下看。
我们在上面已经清楚要解决的就是首尾图片间的切换问题,所以在引入多一张图片之后,可以让轮播从倒数第二张图片(在没有引入图片之前的最后一张图片)切换到最后一张图片(新引入的图片)的动画完成之后,再瞬间跳转到第一张图片,请看下图(我把外面容器的overflow:hidden去掉了以便大家理解):

  • 布局

基于原生Javascript的无缝轮播_第2张图片

  • 动图演示轮播过程

基于原生Javascript的无缝轮播_第3张图片

  • 把overflow:hidden加上,利用视觉差之后

基于原生Javascript的无缝轮播_第4张图片
嘿嘿,是不是很神奇,多引入了一张图片我们就把刚才的问题解决了,至于从第一张到最后一张图片的切换,把刚才的过程倒过来就行了。

三、无缝轮播演示

  • 这里我用到了节流函数,如果你还不知道什么是节流函数的话,可以点击下方链接去我另外一篇文章查看。

点我跳转Javascript函数式编程之节流函数

  • 代码部分
/* css代码 */
body{
    background-color: #333;
}
ul{
    position: absolute;
    left: 0;
    list-style: none;
    padding: 0;
}
.wrap{
    overflow: hidden;
    position: relative;
    width: 700px;
    height: 450px;
    margin: 100px auto 0;
}
.wrap .btn{
    position: absolute;
    top: 50%;
    z-index: 1;
    width: 50px;
    height: 80px;
    margin-top: -40px;
    background-color: rgba(0,0,0,.5);
    color: #fff;
    text-align: center;
    line-height: 80px;
    cursor: pointer;
}
.wrap .left{
    left: 0;
}
.wrap .right{
    right: 0;
}
.img-list{
    top: 0;
    margin: 0;
    width: 500%;
    height: 100%;
}
.img-list li{
    float: left;
    width: 700px;
    height: 100%;
}
.img-list li:nth-of-type(1){
    background: url("images/01.jpg") no-repeat center/cover;
}
.img-list li:nth-of-type(2){
    background: url("images/02.png") no-repeat center/cover;
}
.img-list li:nth-of-type(3){
    background: url("images/03.png") no-repeat center/cover;
}
.img-list li:nth-of-type(4){
    background: url("images/04.png") no-repeat center/cover;
}
.img-list li:nth-of-type(5){
    background: url("images/01.jpg") no-repeat center/cover;
}
.tab-list{
    right: 0;
    bottom: 10px;
    width: 100px;
    margin: auto;
}
.tab-list:after{
    content: "";
    display: block;
    clear: both;
}
.tab-list li{
    float: left;
    transition: 1s;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    background-color: #bbb;
    border-radius: 50%;
}
.tab-list li:hover{
    cursor: pointer;
}
.tab-list li:first-child{
    margin-left: 0;
}
.tab-list .on{
    width: 40px;
    border-radius: 8px;
}

<div class="wrap">
    <div class="btn left"><div>
    <div class="btn right">>div>
    <ul class="img-list">
        <li>li>
        <li>li>
        <li>li>
        <li>li>
        <li>li>
    ul>
    <ul class="tab-list">
        <li class="on">li>
        <li>li>
        <li>li>
        <li>li>
    ul>
div>
//js代码
(function(){
        var oImgList = document.getElementsByClassName("img-list")[0],
            aButton = document.getElementsByClassName("btn"),
            aImgLi = document.querySelectorAll(".img-list li"),
            oWidth = parseFloat(getComputedStyle(aImgLi[0]).width),
            oWrap = document.getElementsByClassName("wrap")[0],
            aTab = document.querySelectorAll(".tab-list li");
            len = aImgLi.length,
            index = 0;
        function throttle(fn,time){
            var startTime = new Date();
            return function(){
                var time_ = (new Date() - startTime) >= time;
                if(time_){
                    fn.apply(this);
                    startTime = new Date();
                }
            }
        }
        function btnTab(){
            var t = new Date();
            for(var i = 0,tabLen = aTab.length;i < tabLen;i++){
                (function(i){
                    aTab[i].onclick = function(){
                        if(new Date() - t >= 1000){
                            aTab[index].className = "";
                            if((i - index) === (tabLen - 1)){
                                oImgList.style.transition = 0 + "s";
                                oImgList.style.left = -oWidth*(len-1) + "px";
                                index = len - 2;
                                setTimeout(function(){
                                    oImgList.style.transition = 1 + "s";
                                    oImgList.style.left = -oWidth*(index) + "px";
                                },1000/60);
                            }
                            else if((i - index) === (1 - tabLen)){
                                oImgList.style.left = -oWidth*(len - 1) + "px";
                                index = 0;
                                setTimeout(function(){
                                    oImgList.style.transition = 0 + "s";
                                    oImgList.style.left = index + "px";
                                },1000);
                            }
                            else{
                                oImgList.style.left = -oWidth*(i) + "px";
                                oImgList.style.transition = 1 + "s";
                            }
                            index = i;
                            this.className = "on";
                            t = new Date();
                        }
                    }
                })(i);
            }
        }
        function btnPre(){
            index--;
            if(index < 0){
                oImgList.style.transition = 0 + "s";
                oImgList.style.left = -oWidth*(len-1) + "px";
                aTab[0].className = "";
                index = len - 2;
                aTab[index].className = "on";
                setTimeout(function(){
                    oImgList.style.transition = 1 + "s";
                    oImgList.style.left = -oWidth*(index) + "px";
                },1000/60);
            }
            else{
                oImgList.style.transition = 1 + "s";
                oImgList.style.left = -oWidth*(index) + "px";
                aTab[index + 1].className = "";
                aTab[index].className = "on";
            }
        }
        function btnNext(){
            index++;
            oImgList.style.transition = 1 + "s";
            if(index === len-1){
                oImgList.style.left = -oWidth*index + "px";
                aTab[len - 2].className = "";
                index = 0;
                aTab[index].className = "on";
                setTimeout(function(){
                    oImgList.style.transition = 0 + "s";
                    oImgList.style.left = index + "px";
                },1000);
            }
            else{
                oImgList.style.left = -oWidth*index + "px";
                aTab[index - 1].className = "";
                aTab[index].className = "on";
            }
        }
        aButton[0].onclick = throttle(btnPre,1000);
        aButton[1].onclick = throttle(btnNext,1000);
        btnTab();
        var timer = setInterval(btnNext,5000);
        oWrap.onmouseover = function(){
            clearInterval(timer);
        }
        oWrap.onmouseout = function(){
            timer = setInterval(btnNext,5000);
        }
    })();
  • demo演示

无缝轮播演示demo

四、无缝轮播的改进

在上面的无缝轮播中,可以发现对于不是相邻的两张图片的切换也并不是直接切换的,而是会过渡中间的图片再切换到目标图片,如下图:

解决办法就是把除了当前显示的图片全都设置成display:none,这样做的好处就是display:none的元素不占据位置!比如说从第一张切换到第三张,因为第二张是display:none,第三章需要显示所以display:block,由于第二张图片不占据位置的原因第三张图片会在第一张图片之后,因此就达到了从第一张直接切换到第三张的效果。

  • 动图演示(没有overflow:hidden)


(有overflow:hidden)

  • 改进后的代码
/* css代码 */
body{
    background-color: #333;
}
ul{
    position: absolute;
    left: 0;
    list-style: none;
    padding: 0;
}
.wrap{
    overflow: hidden;
    position: relative;
    width: 700px;
    height: 450px;
    margin: 100px auto 0;
}
.wrap .btn{
    position: absolute;
    top: 50%;
    z-index: 1;
    width: 50px;
    height: 80px;
    margin-top: -40px;
    background-color: rgba(0,0,0,.5);
    color: #fff;
    text-align: center;
    line-height: 80px;
    cursor: pointer;
}
.wrap .left{
    left: 0;
}
.wrap .right{
    right: 0;
}
.img-list{
    top: 0;
    margin: 0;
    width: 500%;
    height: 100%;
}
.img-list li{
    display: none;
    float: left;
    width: 700px;
    height: 100%;
}
.img-list .active{
    display: block;
}
.img-list li:nth-of-type(1){
    background: url("images/01.jpg") no-repeat center/cover;
}
.img-list li:nth-of-type(2){
    background: url("images/02.png") no-repeat center/cover;
}
.img-list li:nth-of-type(3){
    background: url("images/03.png") no-repeat center/cover;
}
.img-list li:nth-of-type(4){
    background: url("images/04.png") no-repeat center/cover;
}
.img-list li:nth-of-type(5){
    background: url("images/01.jpg") no-repeat center/cover;
}
.tab-list{
    right: 0;
    bottom: 10px;
    width: 100px;
    margin: auto;
}
.tab-list:after{
    content: "";
    display: block;
    clear: both;
}
.tab-list li{
    float: left;
    transition: 1s;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    background-color: #bbb;
    border-radius: 50%;
}
.tab-list li:hover{
    cursor: pointer;
}
.tab-list li:first-child{
    margin-left: 0;
}
.tab-list .on{
    width: 40px;
    border-radius: 8px;
}

<div class="wrap">
    <div class="btn left"><div>
    <div class="btn right">>div>
    <ul class="img-list">
        <li class="active">li>
        <li>li>
        <li>li>
        <li>li>
        <li>li>
    ul>
    <ul class="tab-list">
        <li class="on">li>
        <li>li>
        <li>li>
        <li>li>
    ul>
div>
//js代码
(function(){
        var oImgList = document.getElementsByClassName("img-list")[0],
            aButton = document.getElementsByClassName("btn"),
            aImgLi = document.querySelectorAll(".img-list li"),
            oWidth = parseFloat(getComputedStyle(aImgLi[0]).width),
            oWrap = document.getElementsByClassName("wrap")[0],
            aTab = document.querySelectorAll(".tab-list li");
            len = aImgLi.length,
            index = 0,
            index_ = 0,
            count = 0;;
        function throttle(fn,time){
            var startTime = new Date();
            return function(){
                var time_ = (((new Date() - startTime) >= time) && (count === index));
                if(time_){
                    fn.apply(this);
                    startTime = new Date();
                    setTimeout(function(){
                        count = index;
                    },1000);
                }
            }
        }
        function btnTab(){
            var t = new Date(),
                direction;
            for(var i = 0,tabLen = aTab.length;i < tabLen;i++){
                (function(i){
                    aTab[i].onclick = function(){
                        if((new Date() - t >= 1000) && (count === index)){
                            index_ = index;
                            i - index > 0 ? direction = true : direction = false;
                            if(this.className !== "on"){
                                aTab[index].className = "";
                                if((i - index) === (tabLen - 1)){
                                    aImgLi[len - 1].className = "active";
                                    aImgLi[0].className = "";
                                    oImgList.style.transition = 0 + "s";
                                    oImgList.style.left = -oWidth + "px";
                                    aTab[0].className = "";
                                    index = len - 2;
                                    aImgLi[index].className = "active";
                                    setTimeout(function(){
                                        oImgList.style.transition = 1 + "s";
                                        oImgList.style.left = 0 + "px";
                                    },1000/60);
                                    setTimeout(function(){
                                        aImgLi[len - 1].className = "";
                                    },1000);
                                }
                                else if((i - index) === (1 - tabLen)){
                                    oImgList.style.transition = 1 + "s";
                                    oImgList.style.left = -oWidth + "px";
                                    aTab[len - 2].className = "";
                                    aImgLi[len - 1].className = "active";
                                    index = 0;
                                    aTab[index].className = "on";
                                    setTimeout(function(){
                                        oImgList.style.transition = 0 + "s";
                                        oImgList.style.left = index + "px";
                                        aImgLi[index].className = "active";
                                        aImgLi[len-2].className = "";
                                        aImgLi[len-1].className = "";
                                    },1000);
                                }
                                else{
                                    if(direction){
                                        oImgList.style.left = -oWidth + "px";
                                        oImgList.style.transition = 1 + "s";
                                        setTimeout(function(){
                                            aImgLi[index_].className = "";
                                            oImgList.style.left = 0 + "px";
                                            oImgList.style.transition = 0 + "s";
                                        },1000);
                                    }
                                    else{
                                        oImgList.style.transition = 0 + "s";
                                        oImgList.style.left = -oWidth + "px";
                                        aImgLi[index].className = "active";
                                        setTimeout(function(){
                                            oImgList.style.transition = 1 + "s";
                                            oImgList.style.left = 0 + "px";
                                        },1000/60);
                                        setTimeout(function(){
                                            aImgLi[index_].className = "";
                                        },1000);
                                    }
                                    index = i;
                                    aImgLi[index].className = "active";
                                }
                                this.className = "on";
                                t = new Date();
                                setTimeout(function(){
                                    count = index;
                                },1000);
                            }
                        }
                    }
                })(i);
            }
        }
        function btnPre(){
            index--;
            if(index < 0){
                aImgLi[len - 1].className = "active";
                aImgLi[0].className = "";
                oImgList.style.transition = 0 + "s";
                oImgList.style.left = -oWidth + "px";
                aTab[0].className = "";
                index = len - 2;
                aImgLi[index].className = "active";
                aTab[index].className = "on";
                setTimeout(function(){
                    oImgList.style.transition = 1 + "s";
                    oImgList.style.left = 0 + "px";
                },1000/60);
                setTimeout(function(){
                    aImgLi[len - 1].className = "";
                },1000);
            }
            else{
                oImgList.style.transition = 0 + "s";
                oImgList.style.left = -oWidth + "px";
                aTab[index + 1].className = "";
                aTab[index].className = "on";
                aImgLi[index].className = "active";
                setTimeout(function(){
                    oImgList.style.transition = 1 + "s";
                    oImgList.style.left = 0 + "px";
                },1000/60);
                setTimeout(function(){
                    aImgLi[index + 1].className = "";
                },1000);
            }
        }
        function btnNext(){
            index++;
            oImgList.style.transition = 1 + "s";
            if(index === len-1){
                oImgList.style.left = -oWidth + "px";
                aTab[len - 2].className = "";
                aImgLi[index].className = "active";
                index = 0;
                aTab[index].className = "on";
                setTimeout(function(){
                    oImgList.style.transition = 0 + "s";
                    oImgList.style.left = index + "px";
                    aImgLi[index].className = "active";
                    aImgLi[len-2].className = "";
                    aImgLi[len-1].className = "";
                },1000);
            }
            else{
                oImgList.style.left = -oWidth + "px";
                aTab[index - 1].className = "";
                aTab[index].className = "on";
                aImgLi[index].className = "active";
                setTimeout(function(){
                    oImgList.style.transition = 0 + "s";
                    aImgLi[index - 1].className = "";
                    oImgList.style.left = 0 + "px";
                },1000);
            }
            setTimeout(function(){
                count = index;
            },1000);
        }
        aButton[0].onclick = throttle(btnPre,1000);
        aButton[1].onclick = throttle(btnNext,1000);
        btnTab();
        var timer = setInterval(btnNext,5000);
        oWrap.onmouseover = function(){
            clearInterval(timer);
        }
        oWrap.onmouseout = function(){
            timer = setInterval(btnNext,5000);
        }
    })();
  • 改进后的无缝轮播demo演示

改进后的无缝轮播demo演示

  • 分享一个我自己做的全屏无缝轮播(更新于2018.8.27晚21点)

这个无缝轮播我做了一些处理,也就是只有每个动画完成了下一个选项卡点击事件或者左右两边的按钮点击事件才会触发,这样做也是符合业务逻辑,对了,我在里面添加了背景音乐,右上角有个播放按钮,点击可以关闭音乐哈~
GTAV–全屏无缝轮播(有背景音乐)
GTAV–全屏无缝轮播(无背景音乐)

五、结束语

本文仅仅提到了无缝轮播,其实还有很多优秀的轮播效果,但是由于目前能力有限,还驾驭不了~所以就到这里啦,总之任重而道远,最后感谢阅读咯~

你可能感兴趣的:(基于原生Javascript的无缝轮播)