[JavaScript]继续完善无缝轮播

无缝轮播

完整代码:GitHub

效果预览:GitHub

之前的轮播思路:

1:图片主要使用flex定位加上transform:translateX(),配合JS代码,完成图片切换。缺点:不能进行无缝轮播,图片进行到最后一张要原路返回切换到第一张。

开始时

结束时

2:图片主要使用position:absolute定位,加上状态机,配合JS代码,完成轮播。缺点:只能无缝轮播,不能点击按钮跳转到某一张图片。

详情请戳这里

开始时

跳转中

跳转中

跳转后


我们能不能既能用按钮控制图片轮播的同时,还可以让他进行无缝自动轮播?

思路:
把轮播的第一张图片A1复制到最后一张图片后面,命名为C1,把最后一张图片A(n)复制到第一张图片前面,命名为C2;
每当点击按钮从第一张图片直接切换到最后一张图片的时候,不是切到A(n),而是切到C2,然后再用JS控制隐藏切换动画,从C2切到A(n);每当点击按钮从最后一张图片切换到第一张图片时,不是切到A1,而是切到C1,然后再用JS控制隐藏切换动画,从C1切到A1;其他图片照常切换。

真正的轮播过程是这样的:

当点击按钮想要直接从A1跳转到C1时:
开始时

轮播中

轮播结束

当点击按钮想要直接从A3跳转到A1时:

开始时

轮播时

轮播结束

除了第一张图片和最后一张图片,其他图片照常轮播:

轮播

轮播

轮播

既然了解了这个轮播的思路,开始coding:


构建HTML

<div>
    <p>轮播效果图4</p>
    <div class="window4">
        <div class="images4" id="images4">
            <img src="./img/function-01.jpg" alt="" width=960 height=540>
            <img src="./img/git-01.jpg" alt="" width=960 height=540 >
            <img src="./img/JQUERY-01.jpg" alt="" width=960 height=540>
            <img src="./img/内存-01.jpg" alt="" width=960 height=540>
            <img src="./img/数组-01.jpg" alt="" width=960 height=540>
        </div>
    </div>
    <div class="controls" id="controls">
        <button id="prev">上一张</button>
        <button id="next">下一张</button>
    </div>
    <div class="bnCtrl4" id="bnCtrl4">
        <button >第1张</button>
        <button >第2张</button>
        <button >第3张</button>
        <button >第4张</button>
        <button >第5张</button>
    </div>
</div>

构建CSS

主要是构建一个轮播框和利用flex进行图片排列。

.window4 {
     960px;
    border: 1px solid red;
    margin: 30px auto;
    overflow: hidden;
}
.images4 {
    display: flex;
    transition: all 1s;
}
.images4 img{
     100%;
}
.bnCtrl4 {
    text-align: center;
}
.controls{
    text-align: center;
}
.controls button{
    margin: 5px;
}
.bnCtrl4 button{
    margin: 5px;
}

先实现图片切换功能

先模拟每一张图片是怎么进行轮播的:

// jQuery获取图片
let $images4 = $('#images')
let $imgs = $images4.children('img')

//获取按钮
let $button = $('#bnCtrl4 button')

每当点击按钮时,对应的图片进行切换:

// 切换到下一张图片
$button4.eq(0).on('click',function(){
    $images4.css({transform:'translateX(-960px)'})
})
$button4.eq(1).on('click',function(){
    $images4.css({transform:'translateX(-960px)'})
})
$button4.eq(2).on('click',function(){
    $images4.css({transform:'translateX(-960px)'})
})
$button4.eq(3).on('click',function(){
    $images4.css({transform:'translateX(-960px)'})
})
$button4.eq(4).on('click',function(){
    $images4.css({transform:'translateX(-960px)'})
})

再实现图片无缝切换

克隆图片

克隆第一张图片放在最后一张图片的后面,克隆最后一张图片放在第一张图片的前面:

$firstCopy = $img.eq(0).clone(true)
$lastCopy = $img.eq($img.length - 1).clone(true)

$images4.addchild($firstCopy)
$images4.prepend($lastCopy)

// 封装成函数
function makeFakeSlides(){
    let $firstCopy = $imgs.eq(0).clone(true)
    let $lastCopy = $imgs.eq($imgs.length-1).clone(true)
    $images4.append($firstCopy)
    $images4.prepend($lastCopy)
}

区分第一个按钮和最后一个按钮

首先给每个按钮一个current,以代表当前的位置,相当于设置一个路标。

//设置初始路标
let current = 0
$images4.css({transform:'translateX(-960px)'})

$button4.eq(0).on('click',function(){
    $images4.css({transform:'translateX(-960px)'})
    current = 0
})
$button4.eq(1).on('click',function(){
    $images4.css({transform:'translateX(-1920px)'})
    current = 1
})
$button4.eq(2).on('click',function(){
    $images4.css({transform:'translateX(-2880px)'})
    current = 2
})
$button4.eq(3).on('click',function(){
    $images4.css({transform:'translateX(-3840px)'})
    current = 3
})
$button4.eq(4).on('click',function(){
    $images4.css({transform:'translateX(-4800px)'})
    current = 4
})

在正常情况下,如从1-2-3-4,按钮2按下时会接收按钮1传递的current=0,然后把current改为1;按钮3按下时,会接收按钮2传递的current=1,然后把current改为2;...以此类推;

特殊情况是,从按钮5按到按钮1;或者是从按钮1直接按到按钮5,这其中的转变过程我们要用JS来加以判断:

//设置初始路标
let current = 0
$images4.css({transform:'translateX(-960px)'})

$button4.eq(0).on('click',function(){
    if(current == 4){
        //直接切换到第一张图片(即我们复制的C2)
        $images4.css({transform:'translateX(0px)'})
    }else{
        $images4.css({transform:'translateX(-960px)'})
        current = 0
    }
})
$button4.eq(1).on('click',function(){
    $images4.css({transform:'translateX(-1920px)'})
    current = 1
})
$button4.eq(2).on('click',function(){
    $images4.css({transform:'translateX(-2880px)'})
    current = 2
})
$button4.eq(3).on('click',function(){
    $images4.css({transform:'translateX(-3840px)'})
    current = 3
})
$button4.eq(4).on('click',function(){
    if(current == 0){
        //直接切换到最后一张图片(即我们复制的C1)
        $images4.css({transform:'translateX(-5760px)'})
    }else{
        $images4.css({transform:'translateX(-4800px)'})
        current = 4
    }
})

接下来切换图片,从克隆的图片上悄悄地快速地转到真正的图片上:

利用小技巧 offset(),隐藏切换动画。

//设置初始路标
let current = 0

$button4.eq(0).on('click',function(){
    if(current == 4){
        //直接切换到第一张图片(即我们复制的C2)
        $images4.css({transform:'translateX(0px)'})
            .one('transitionend',function(){
                 $images4.hide()
                    .offset()
                    $images4.css({transform:'translateX(-960px)'})
                    .show()
                })
            })
    }else{
        $images4.css({transform:'translateX(-960px)'})
        current = 0
    }
})
$button4.eq(1).on('click',function(){
    $images4.css({transform:'translateX(-1920px)'})
    current = 1
})
$button4.eq(2).on('click',function(){
    $images4.css({transform:'translateX(-2880px)'})
    current = 2
})
$button4.eq(3).on('click',function(){
    $images4.css({transform:'translateX(-3840px)'})
    current = 3
})
$button4.eq(4).on('click',function(){
    if(current == 0){
        //直接切换到最后一张图片(即我们复制的C1)
        $images4.css({transform:'translateX(-5760px)'})
         .one('transitionend',function(){
                $images4.hide()
                .offset()
                $images4.css({transform:'translateX(-4800px)'})
                .show()
            })
    }else{
        $images4.css({transform:'translateX(-4800px)'})
        current = 4
    }
})

这么简陋重复的代码,就完成了无缝轮播的功能了!

优化代码

给按钮添加事件代理,把代码进一步抽象出来:

function bindEvents(){
    $('#bnCtrl4').on('click','button',function(e){

        //获取当前点击按钮
        let $buttons = $(e.currentTarget)

        //获取按钮的位置下标
        let index = $buttons.index()

        if(current === $button4.length-1 && index === 0){
        $images4.css({transform:`translateX(${-($button4.length+1) * 960}px)`})
        .one('transitionend',function(){
            $images4.hide()
                .offset()
                $images4.css({transform:`translateX(${-(index+1)*960}px)`})
                .show()
                })
        }else if(current === 0 && index === $button4.length-1){
            $images4.css({transform:`translateX(0px)`})
            .one('transitionend',function(){
                $images4.hide()
                    .offset()
                    $images4.css({transform:`translateX(${-(index+1) * 960}px)`})
                    .show()
                })
        }else{
            $images4.css({transform:`translateX(${-(index+1) * 960}px)`})
        }
    current = index
    })
}

进一步抽象

把轮播功能提取出来,可以提供接口,添加更多的功能:

function bindEvents(){
    $('#bnCtrl4').on('click','button',function(e){
        let $buttons = $(e.currentTarget)
        let index = $buttons.index() 
        goToSlides(index)
    })
}

function goToSlides(index){
    if(index > $button4.length - 1){
        index = 0
    }else if(index < 0 ){
        index = $button4.length -1
    }
    if(current === $button4.length-1 && index === 0){
        $images4.css({transform:`translateX(${-($button4.length+1) * 960}px)`})
        
        // 当动画结束时添加一个时间,执行函数,让他快速转回第一张图片
        .one('transitionend',function(){
            
            //小技巧,先hide()再show(),中断动画
            $images4.hide()
                    .offset()
                    $images4.css({transform:`translateX(${-(index+1)*960}px)`})
                    .show()
                })
    }else if(current === 0 && index === $button4.length-1){
        $images4.css({transform:`translateX(0px)`})
        
        // 当动画结束时添加一个时间,执行函数,让他快速转回第一张图片
        .one('transitionend',function(){
            
            //小技巧,先hide()再show(),中断动画
            $images4.hide()
                    .offset()
                    $images4.css({transform:`translateX(${-(index+1) * 960}px)`})
                    .show()
                })
    }else{
        $images4.css({transform:`translateX(${-(index+1) * 960}px)`})
    }
    current = index
}

添加自动轮播

这就是为什么要提取出goToSlides()的原因:

setInterval(function(){
    goToSlides(current + 1)
},2000)

添加其他功能

//上下页功能
$(next).on('click',function(){
    goToSlides(current + 1)
})

$(prev).on('click',function(){
    goToSlides(current - 1)
})

//鼠标移入,轮播暂停;鼠标移出,轮播继续
let thisTimer = setInterval(function(){
    goToSlides(current + 1)
},2000)

$('.window4').on('mouseenter',function(){
    window.clearInterval(thisTimer)
}).on('mouseleave',function(){
    thisTimer = setInterval(function(){
        goToSlides(current + 1)
    },2000)
})

总结

总的来说,自己创建一个轮播的过程是十分鬼畜的!要考虑很多东西,即使是听老师讲一遍,自己再做出来,对于现在的我也有难度。
这里更多的是直接给出结果,而没有更多地给出思考的过程,这是一种失误,也是我一直想要避免、一直在更正的东西。
只能多看看人家的博文,多学习了。

原文地址:https://www.cnblogs.com/No-harm/p/9601547.html