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