jQuery实现轮播(二)

优化《jQuery实现轮播(一)》中实现的效果,并添加按钮可实现前后图片手动切换。最最重要的是,让这个轮播更加符合大众审美。

一、解决Bug

1、持续轮播

在我的博客jQuery实现轮播(一)中,简单的实现了一个轮播图效果。
这个轮播看起来没什么问题,但是在轮播播放的过程中如果我们切换到了其他页面的话,也就是轮播页面处于用户看不到的情况下,隔几秒钟再去看轮播页面会发现轮播已经乱了。这是为什么呢?主要原因是像setIntervalsetTimeout这类函数在页面执行中,如果当前页面不处于用户可视范围内的话,会自动降低循环频率。解决此问题的方案为:为document添加visibilitychange事件,监听当前页面是否隐藏,代码如下:

1
2
3
4
5
6
7
document.addEventListener('visibilitychange',function(){
if(document.hidden){ //为true时则表示此页面被切出
//此时暂停setInterval定时器
}else{
//继续setInterval定时器
}
})

此事件监听触发的条件为:切换屏幕、浏览器各个tab页之间的切换。

2、非连续切换

以上轮播能够完美实现循环连续播放,但是在实际操作过程中,除了循环播放外,点击某按钮(或其他可点击元素)能够跳转到指定轮播图。为了能够实现跳转到固定图片并且还能够循环连续播放,除了添加按钮增加上翻/下翻功能外,还需要考虑从第一张到最后一张以及最后一张到第一张轮播图连续播放的问题。

二、jQuery实现轮播效果重构

实现首尾两张连续播放的问题,可以在轮播图片前后分别添加尾图和收图,如果有三张图:1、2、3需要参与轮播的话,那么添加首尾图后图片的顺序为:3、1、2、3、1。根据这个来进行接下来的重构。

1、初始代码布局与样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>swiper</title>
<link rel="stylesheet" href="./css/swiper.css">
</head>
<body>
<div class="window">
<div class="images" id="slides">
<img src="./img/01.png" width="200" height="200" alt="">
<img src="./img/02.png" width="200" height="200" alt="">
<img src="./img/03.png" width="200" height="200" alt="">
<img src="./img/04.png" width="200" height="200" alt="">
</div>
</div>
<div style="text-align: center;">
<button>1</button>
<button>2</button>
<button>3</button>
<button>4</button>
</div>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="./js/swiper.js"></script>
</body>
</html>

样式为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
*{
padding: 0px;
margin: 0px;
}
.images > div{
width: 200px;
height: 200px;
background: #fcc;
line-height: 200px;
text-align: center;
}
.images{
display: flex;
justify-content: flex-start;
transition: all 0.3s ease-in-out;
align-content: center;
}
.window{
width: 200px;
height: 200px;
overflow: hidden;
margin: 0 auto;
}
.red{
color: red;
}
button{
padding: 4px 10px;
}

JS为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let $imgs = $('img');
let $images = $('.images');
let $btns = $('button');
let $slides = $('#slides');
$btns.eq(0).on('click',function(){
$slides.css({
'transform' : 'translateX(0px)'
})
})
$btns.eq(1).on('click',function(){
$slides.css({
'transform' : 'translateX(-200px)'
})
})
$btns.eq(2).on('click',function(){
$slides.css({
'transform' : 'translateX(-400px)'
})
})
$btns.eq(3).on('click',function(){
$slides.css({
'transform' : 'translateX(-600px)'
})
})

以上能够完成点击button切换到对应的图片。

2、优化代码

为结构头尾分别添加末图/首图,并完成无缝轮播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
let $imgs = $('img');
let $images = $('.images');
let $btns = $('button');
let $slides = $('#slides');
let $window = $('.window');
let current = 0;
let step = $window.width();

init(); //初始化
bindEvents(); //事件绑定


function bindEvents(){
$btns.eq(0).on('click',function(){
if(current === 3){
$slides.css({
'transform' : 'translateX(-1000px)'
}).one('transitionend',function(){
console.log('从最后一张到第一张')
$slides.hide().offset();
$slides.css({
'transform' : 'translateX(-200px)'
}).show();
})
}else{
$slides.css({
'transform' : 'translateX(-200px)'
})
}
current = 0;
})
$btns.eq(1).on('click',function(){

$slides.css({
'transform' : 'translateX(-400px)'
})
current = 1;
})
$btns.eq(2).on('click',function(){

$slides.css({
'transform' : 'translateX(-600px)'
})
current = 2;
})
$btns.eq(3).on('click',function(){
if(current === 0){
console.log('从第一张到最后一张');
$slides.css({
'transform' : 'translateX(0px)'
}).one('transitionend',function(){
$slides.hide().offset();
$slides.css({
'transform' : 'translateX(-800px)'
}).show();
})
}else{
$slides.css({
'transform' : 'translateX(-800px)'
})
}
current = 3;
})
}

function init(){
let $first = $imgs.eq(0).clone(true);
let $last = $imgs.eq($imgs.length - 1).clone(true);
$images.append($first).prepend($last).hide().offset();
$images.css({
transform:'translateX(-'+ $window.width() +'px)'
}).show();
}

三、优化

1、事件通用

上述代码的button事件只是针对四张图片来写的,为提高通性,代码需修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
let $imgs = $('img');
let $images = $('.images');
let len = $imgs.length;
let $btns = $('button');
let $slides = $('#slides');
let $window = $('.window');
let current = 0;
let step = $window.width();

init(); //初始化
bindEvents(); //事件绑定


function bindEvents(){
$('#buttonWrapper').on('click','button',function(e){
let $target = $(e.currentTarget);
let idx = $target.index();
if(current === len-1 && idx === 0){
$slides.css({
'transform' : `translateX(-${step * (len+1)}px)`
}).one('transitionend',function(){
$slides.hide().offset();
$slides.css({
'transform' : `translateX(-${step}px)`
}).show();
})
}else if(current === 0 && idx === len-1){
$slides.css({
'transform' : 'translateX(0px)'
}).one('transitionend',function(){
$slides.hide().offset();
$slides.css({
'transform' : `translateX(-${step * len}px)`
}).show();
})
}else{
$slides.css({
'transform' : `translateX(-${step * (idx + 1)}px)`
})
}
current = idx;
})
}
function init(){
let $first = $imgs.eq(0).clone(true);
let $last = $imgs.eq($imgs.length - 1).clone(true);
$images.append($first).prepend($last).hide().offset();
$images.css({
transform:'translateX(-'+ $window.width() +'px)'
}).show();
}

2、添加上一页/下一页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
...
//HTML
<div class="controls">
<button id="prev">上一张</button>
<button id="next">下一张</button>
</div>
...
//JS
$('#prev').on('click',function(){
goToSlide(current-1);
})
$('#next').on('click',function(){
goToSlide(current+1);
})
function bindEvents(){
$('#buttonWrapper').on('click','button',function(e){
let $target = $(e.currentTarget);
let idx = $target.index();
goToSlide(idx);
})
}
function goToSlide(idx){
if(idx > len - 1){
idx = 0
}else if(idx < 0){
idx = len - 1;
}
if(current === len-1 && idx === 0){
$slides.css({
'transform' : `translateX(-${step * (len+1)}px)`
}).one('transitionend',function(){
$slides.hide().offset();
$slides.css({
'transform' : `translateX(-${step}px)`
}).show();
})
}else if(current === 0 && idx === len-1){
$slides.css({
'transform' : 'translateX(0px)'
}).one('transitionend',function(){
$slides.hide().offset();
$slides.css({
'transform' : `translateX(-${step * len}px)`
}).show();
})
}else{
$slides.css({
'transform' : `translateX(-${step * (idx + 1)}px)`
})
}
current = idx;
}

3、添加自动播放以及鼠标悬停暂停播放

1
2
3
4
5
6
7
8
9
10
let t = setInterval(function(){
goToSlide(current+1);
},2000);
$window.on('mouseenter',function(){
clearInterval(t);
}).on('mouseleave',function(){
setInterval(function(){
goToSlide(current+1);
},2000);
})

以上代码预览地址