原生js实现图片轮播

前言

寒假在家随便做个网站demo的时候用到了antd的轮播,当时没有找到左边有上下页按钮的示例,回到学校,发现实验的项目也有轮播,不过是用angular做的,这个轮播只有上下页按钮,没有antd的中间可任意选择第几章图片的工具,就想着自己用js实现一下轮播功能,把这两种功能都合起来。

感谢 十五分钟用 JavaScript 基础写一个图片轮播效果 + 思路详解 提供的思路,在实现的时候基本是以上博客的思想,有改动。

主要从三个方面记录自己的实现过程,有部分自己的想法,也有待优化的部分。

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div class="img-content">
<div class="img-carousel">
<div class="img-container"><img src="./images/1.jpg" alt=""></div>
<div class="img-container"><img src="./images/2.jpg" alt=""></div>
<div class="img-container"><img src="./images/3.jpg" alt=""></div>
</div>
<div class="arrow">
<span class="left-arrow">&lt;</span>
<span class="right-arrow">&gt;</span>
</div>

<div class="dot-choose">
<span class="dot" style="background-color: #D4D4D4"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</div>

html分三个部分,图片显示、左右方向键以及底部四个圆角矩形可供任意选择图片。
(习惯在img标签外面套一层div)

css

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
* {
margin: 0;
padding: 0;
}

.img-content {
width: 800px;
position: relative;
overflow: hidden;
margin: auto;
}

.img-carousel {
width: 4000px;
display: inline-block;
overflow: hidden;
transition: all 2s;
}

.img-container {
width: 800px;
height: 600px;
text-align: center;
line-height: 600px;
translate: all 2s;
float: left;
}

.img-container img {
width: 100%;
vertical-align: middle;
}

.arrow {
position: absolute;
top: 289px;
font-size: 36px;
z-index: 999;
width: 800px;
color: white;
}
.right-arrow {
float: right;
}

.arrow:hover, .dot:hover {
cursor: pointer;
}

.dot-choose {
position: absolute;
bottom: 100px;
width: 600px;
text-align: center;
z-index: 999;
margin-left: 300px;
}

.dot{
float: left;
width: 50px;
height: 5px;
border-radius: 100px;
background-color: #D4D4D4;
margin-right: 20px;
}

.dot:hover {
background-color: white;
}

css主要有两点:

  • img标签的图片全部排成一行,设置外层图片显示区域(img-carouse)的宽度为一定值(此处设为800px),多余的隐藏,即可每次显示一张图片。
  • img-carouse 设置transition,可供移动。

Javascript

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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
var idx = 0;
var timer;
window.onload = function() {
var imgCarousel = document.getElementsByClassName("img-carousel")[0];
var imgContainer = document.getElementsByClassName("img-container");

var prev = document.getElementsByClassName("left-arrow")[0];
var next = document.getElementsByClassName("right-arrow")[0];
var arrows = document.getElementsByClassName("arrow");

var dots = document.getElementsByClassName('dot');

var count = imgContainer.length;

slideImg();

function changeDotBg(index) {
for(var j = 0; j < dots.length; ++j) {
dots[j].style.backgroundColor = "#D4D4D4";
}

dots[index].style.backgroundColor = "white";
}

function slideImg() {
timer = setInterval(function() {
idx ++ ;
if(idx < count) {

imgCarousel.style.transform = "translate(" + -800 * idx + "px)";
imgCarousel.style.transition = "2s";
} else {
imgCarousel.style.transition = "0s";
imgCarousel.style.transform = "translate(0px)";
idx = 0;
}

changeDotBg(idx);

}, 2000);


}

for (var i = 0; i < arrows.length; ++i) {
arrows[i].onmouseover = function() {
clearInterval(timer);
}

arrows[i].onmouseout = function() {
slideImg();
}
}


prev.onclick = function() {
if(idx !== 0) {
idx --;
imgCarousel.style.transition = "2s";
} else {
idx = count - 1;
imgCarousel.style.transition = "0s";
}
changeDotBg(idx);
imgCarousel.style.transform = "translate(" + -800 * idx + "px)";
}

next.onclick = function() {
if(idx < count - 1) {
idx ++;
imgCarousel.style.transition = "2s";
} else {
idx = 0;
imgCarousel.style.transition = "0s";
}
changeDotBg(idx);
imgCarousel.style.transform = "translate(" + -800 * idx + "px)";
}

for(var i = 0; i < dots.length; ++i) {
dots[i].index = i;
dots[i].onclick = function() {
clearInterval(timer);
changeDotBg(this.index);
imgCarousel.style.transition = "0s";
imgCarousel.style.transform = "translate(" + -800 * this.index + "px)";
idx = this.index;

}
}
}

Javascript部分代码也是分为三块:图片定时滑动到下一张、左右功能键选择、底部矩形框选择。

图片定时滑动

  • 使用一个定时器setInterval,可在固定时间之后更换到下一张
  • 显示区域图片更换用transition移动图片宽度(此处为800px)
  • 计时器对象timer设置为全局变量,可供某些时刻停止计时。
  • idx记录当前显示是第几张图片,全局变量
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
var idx = 0;
var timer;

window.onload = function() {
var imgCarousel = document.getElementsByClassName("img-carousel")[0];
var imgContainer = document.getElementsByClassName("img-container");

var dots = document.getElementsByClassName('dot');

var count = imgContainer.length;

slideImg();

function slideImg() {
timer = setInterval(function() {
idx ++ ;
if(idx < count) {

imgCarousel.style.transform = "translate(" + -800 * idx + "px)";
imgCarousel.style.transition = "2s";
} else {
imgCarousel.style.transition = "0s";
imgCarousel.style.transform = "translate(0px)";
idx = 0;
}
changeDotBg(idx);
}, 2000);

}
}
滑动到最后一张时应注意

先判断当前图片索引号是否小于总图片数量,若小于则直接滑动到下一张,否则先取消滑动动画(duration设置为0s),然后直接跳到第一张。若按最开始参考链接的思路,最后一张会滑动到第一张,影响视觉效果。但直接跳到第一张的做法也不太可取,此处也是待改进的点。之前也想过最后一张图片后接上第一张图片,这样可以从最后一张(视觉上的)先滑动到第一张(拼接之后为实际最后一张图),然后快速定位到第一张,但此处多引入了一个图片元素,就没有采取此种做法。(如何实现动画效果一样的循环轮播?

上下页按钮

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
var prev = document.getElementsByClassName("left-arrow")[0];
var next = document.getElementsByClassName("right-arrow")[0];
var arrows = document.getElementsByClassName("arrow");

for (var i = 0; i < arrows.length; ++i) {
arrows[i].onmouseover = function() {
clearInterval(timer);
}

arrows[i].onmouseout = function() {
slideImg();
}
}


prev.onclick = function() {
if(idx !== 0) {
idx --;
imgCarousel.style.transition = "2s";
} else {
idx = count - 1;
imgCarousel.style.transition = "0s";
}
changeDotBg(idx);
imgCarousel.style.transform = "translate(" + -800 * idx + "px)";
}

next.onclick = function() {
if(idx < count - 1) {
idx ++;
imgCarousel.style.transition = "2s";
} else {
idx = 0;
imgCarousel.style.transition = "0s";
}
changeDotBg(idx);
imgCarousel.style.transform = "translate(" + -800 * idx + "px)";
}

就是当前图片索引idx 加1与减1的做法,需要注意的点与上相同,也是最后一张点击向右滑动到最后一张,第一张点击向左滑动到第一张的问题。由于是方向键控制,所以直接跳转在视觉上也不是很突兀,或许方向键可以做成直接切换的效果(duration:0s)。

底部矩形选择图片

这里将切换矩形背景色封装为一个函数,方便其他功能调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var dots = document.getElementsByClassName('dot');

function changeDotBg(index) {
for(var j = 0; j < dots.length; ++j) {
dots[j].style.backgroundColor = "#D4D4D4";
}

dots[index].style.backgroundColor = "white";
}

for(var i = 0; i < dots.length; ++i) {
dots[i].index = i;
dots[i].onclick = function() {
clearInterval(timer);
changeDotBg(this.index);
imgCarousel.style.transition = "0s";
imgCarousel.style.transform = "translate(" + -800 * this.index + "px)";
idx = this.index;

}
}

待改进点

如前所述,主要是实现动画效果一致的循环轮播功能。