循环轮播图的各种实现

undefined

轮播图的各种实现方式,没有最好的方式,只有更加适用的方式。这里写了超多代码,然而,让文章变得好臃肿好卡。所以可能会考虑删减,只留核心以及原理逻辑

轮播图的原理

虽然轮播图的实现方式有很多种,但是其实究其原理都是一样的。

首先,外部的用来约束轮播图的大小(当然也可以让内部容器撑开),最重要的是设置overflow:hidden来隐藏子容器超出部分。

其次,子容器放置所有轮播图的区块。一块的大小和父容器的大小一致,如果需要横向轮播则需要将其定位到横向。(float:left再配合width:300%(代表三张轮播图)或者position:absolute;left:100%;以备随时滚动过来。

最后,通过改变子容器的位置margin-left或者left等定位属性,将需要展示的轮播内容移动到父容器的展示位置即可。

再多加点修饰:利用一个全局的常量来记录当前的轮播位置,就可以很轻松地实现到dots点的展示啦。然后添加点击事件,滑动事件,定时器什么的,一个功能丰富的轮播图就出来了。

稍微棘手的就是临界值时候,无限轮播的实现稍微麻烦。以及点击切换如果结合动画容易造成动画错位。

然后就来介绍各种轮播图的实现原理,以及分析一下优劣。当然一下见解不过是我自己手撸了这么多个之后自己的感悟吧。这里不会太多说代码部分,代码部分放在最后哦

CSS3特效动画轮播图(更新于2017.10.19)

平时的轮播图都是很单调地左滑又滑上滑下滑,稍微再酷一点就顶多是利用transform:scale()来实现变大变小。有幸在腾讯课堂的海棠学院看到了css3动画demo,实现更酷炫的轮播图。

原理

抛却一切别的东西。在轮播图的图片区,不再是事先放好所有图片进行超出隐藏然后进行位移。轮播图区只有当前的显示图片,那么其他图片怎么来呢?当然是js动态设置啦。为了酷炫的效果,我们使用相对定位,将图片切割成若干个长方形,再结合background-position:设置图片显示的位置。也就是用若干长方形铺满一张图片,并设置transform:translateY(100%)将小长方形放置在画面之外。之后利用setTimeout函数,进行位移。

1
2
3
4
5
6
7
// div指的是小长方形
// i 指的是当前个数, 可以理解为 为了实现每个长方形不同步地移入画面
function move(div, i) {
setTimeout(function(){
div.style.transform = 'translateY(0)';
}, (i+1)*50);
}

此外,监听最后一个小长方形的动画事件。当动画结束,将所有长方形移除,并且设置图片。

1
2
3
4
lastDiv.addEventListener('transitionend', function(){
$wrapConetent.innerHTML = `<img src="img/${imgNum}.jpg">`;
canMove = true; // 用于节流,避免用户在动画结束之前点击
})

这里效果不方便演示啊,很难讲清楚效果是怎么一个效果。大致描述一下, 就是点击切换时,图片被分割成好多长条,然后依照从中间往两边散开的先后顺序进入页面。

利用前后辅助图实现循环轮播

前后多加一张辅助图 可以实现。这个方法是最初的轮播图实现,大部分功能都能完美实现,唯一缺点就是前后多加了一张图,代码结构上并不好看。实现方式就是margin-left一直负负负负负直到到达末尾后重置为0

  • 无限循环滚动
  • 点击index滚到固定位置
  • dots点的正确显示

不加辅助图则会出现变形,有相关功能的取舍。例如没有辅助图则左右循环的时候最后一张回到第一章会有将内容全部回滚的动画样式。

  1. 不加辅助图 左右循环滚动 但是从最后一张滚到第一张的时候是从右滚到左
  2. 突然发现如果只有3个是可以点击的嘻嘻嘻 毕竟只关乎前后移动,不会出现需要滑动两次的情况

利用绝对定位实现

原理就是将当前项设置为left:0,前一项设置为-100%;其他所有都设置为100%;然后结合animate函数进行动画操作

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<script type="text/javascript">
window.onload = function () {
var className = '.box-father';
var picNum = 5;
var _index = -1;
var _pre = picNum - 1;
var _next = _index + 1;
var $boxFather = document.querySelectorAll(className)[0];
var $boxUl = document.querySelectorAll(className + '> .box')[0];
var $boxLi = $boxUl.children;
var $preBtn = document.querySelectorAll(className + '> .pre')[0];
var $nextBtn = document.querySelectorAll(className + '> .next')[0];
next();
function next() {
_index = (_index + 1) % picNum;
_pre = _index - 1;
if (_pre < 0) {
_pre = picNum - 1;
}
_next = (_index + 1) % picNum;
$boxLi[_index].style.zIndex = '3';
$boxLi[_index].style.backgroundColor = 'rgba(54, 21, 21, 1)';
$($boxLi[_index]).animate({
left: '0'
}, 400);
$boxLi[_next].style.zIndex = '2';
$boxLi[_next].style.backgroundColor = 'rgba(0,0,0,0.6)';
$($boxLi[_next]).animate({
left: '100%'
}, 400);
$boxLi[_pre].style.zIndex = '2';
$boxLi[_pre].style.backgroundColor = 'rgba(0,0,0,0.6)';
$($boxLi[_pre]).animate({
left: '-100%'
}, 400);
for (var i = 0; i < $boxLi.length; i++) {
if (_index != i && _pre != i && _next != i) {
$boxLi[i].style.index = '1';
$boxLi[i].style.left = '100%';
}
}
}
function pre() {
_index = _index - 1;
if (_index < 0) {
_index = picNum - 1;
}
_pre = _index - 1;
if (_pre < 0) {
_pre = picNum - 1;
}
_next = (_index + 1) % picNum;
$boxLi[_index].style.zIndex = '3';
$boxLi[_index].style.backgroundColor = 'rgba(54, 21, 21, 1)';
$($boxLi[_index]).animate({
left: '0'
}, 400);
$boxLi[_next].style.zIndex = '2';
$boxLi[_next].style.backgroundColor = 'rgba(0,0,0,0.6)';
$($boxLi[_next]).animate({
left: '100%'
}, 400);
$boxLi[_pre].style.zIndex = '2';
$boxLi[_pre].style.backgroundColor = 'rgba(0,0,0,0.6)';
$boxLi[_pre].style.left = '-100%';
for (var i = 0; i < $boxLi.length; i++) {
if (_index != i && _pre != i && _next != i) {
$boxLi[i].style.index = '1';
$boxLi[i].style.left = '100%';
}
}
}
$preBtn.addEventListener('click', function () {
console.log(`pre:${_pre};now:${_index}next:${_next}`);
pre();
});
$nextBtn.addEventListener('click', function () {
console.log(`pre:${_pre};now:${_index}next:${_next}`);
next();
});
$('.btn').on('click', 'li', function () {
var preIndex = _index;
var nowIndex = $(this).text() - 1;
var time = preIndex - nowIndex;
_index = nowIndex;
// 等于0直接返回
_next = (_index + 1) % picNum;
_pre = _index - 1;
console.log(_pre);
if (_pre < 0) {
_pre = picNum - 1;
}
if (time === 0) {
return
}
if (time < 0) {
// 目标在右边的位置
// 需要 100设为0 当前设为-100后
$boxLi[preIndex].style.zIndex = '2';
$boxLi[preIndex].style.backgroundColor = 'rgba(0,0,0,0.6)';
$($boxLi[preIndex]).animate({
left: '-100%'
}, 400, function(){
$boxLi[preIndex].style.left = '100%';
$boxLi[_pre].style.left = '-100%';
});
$boxLi[_index].style.left = '100%';
$boxLi[_index].style.zIndex = '3';
$boxLi[_index].style.backgroundColor = 'rgba(54, 21, 21, 1)';
$($boxLi[_index]).animate({
left: '0'
}, 400);
$boxLi[_next].style.left = '100%';
$boxLi[_next].style.zIndex = '2';
$boxLi[_next].style.backgroundColor = 'rgba(54, 21, 21, 1)';
$($boxLi[_next]).animate({
left: '100%'
}, 400);
console.log(`preIndex:${preIndex},_pre:${_pre} `);
} else {
// 目标在左边的位置
// 需要 -100 设为0 当前设为100
$boxLi[preIndex].style.zIndex = '2';
$boxLi[preIndex].style.backgroundColor = 'rgba(0,0,0,0.6)';
$($boxLi[preIndex]).animate({
left: '100%'
}, 400);
$boxLi[nowIndex].style.left = '-100%';
$boxLi[nowIndex].style.zIndex = '3';
$boxLi[nowIndex].style.backgroundColor = 'rgba(54, 21, 21, 1)';
$($boxLi[nowIndex]).animate({
left: '0'
}, 400);
_next = (_index + 1) % picNum;
$boxLi[_next].style.left = '100%';
$boxLi[_next].style.zIndex = '2';
$boxLi[_next].style.backgroundColor = 'rgba(54, 21, 21, 1)';
$($boxLi[_next]).animate({
left: '100%'
}, 400);
$boxLi[_pre].style.left = '-100%';
}
})
}
</script>
</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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
function swiper(className, picNum, animateTime, hasDots) {
var picNum = picNum;
var animateTime = animateTime;
var className = className;
var hasDots = hasDots || false;
var $swiperBox = document.querySelector(className + ' > .swiper-box');
var _time;
var _firstX;
var _index = 0;
var _swiperMarginLeft = 0;
var $swiperInside = $swiperBox.children[0];
var $img = $swiperInside.children[0];
var $btnPre = document.querySelector(className + '> .swiper-btn-pre');
var $btnNext = document.querySelector(className + '> .swiper-btn-next');
var $dotsUl = document.querySelector(className + '> .dots-ul');
var imgWidth = parseInt(window.getComputedStyle($img).getPropertyValue('width'));
_time = setTime();
function next() {
clearTimeout(_time);
_swiperMarginLeft -= imgWidth;
if (-_swiperMarginLeft >= picNum * imgWidth) {
_swiperMarginLeft = 0;
}
$swiperInside.style.marginLeft = _swiperMarginLeft + 'px';
_index = (_index + 1) % picNum;
if(hasDots){
changeDots();
}
_time = setTime();
}
function pre() {
clearTimeout(_time);
_swiperMarginLeft += imgWidth;
if (_swiperMarginLeft > 0) {
_swiperMarginLeft = -(picNum-1) * imgWidth;
}
$swiperInside.style.marginLeft = _swiperMarginLeft + 'px';
if (_index === 0){
_index = picNum;
}
_index = (_index - 1) % picNum;
if(hasDots){
changeDots();
}
_time = setTime();
}
function setTime() {
return setTimeout(function() {
next();
}, animateTime)
}
// 变换dot的class
function changeDots(){
var $dots = $dotsUl.children;
for(var i = 0; i < $dots.length; i++) {
$dots[i].setAttribute('class', 'dots');
if (_index === i) {
$dots[i].setAttribute('class', 'dots on');
}
}
}
// 监听点击时间
$btnPre.addEventListener('click', function() {
pre();
});
$btnNext.addEventListener('click', function() {
next();
});
// 绑定在父级上
if(hasDots){
$dotsUl.addEventListener('click', function(e){
var target = e.target;
var dots = $dotsUl.children;
for (var i = 0; i < dots.length; i++) {
if(target === dots[i]) {
_index = i - 1;
_swiperMarginLeft = -imgWidth * _index;
next();
}
}
});
}
// 监听拖动事件
$swiperBox.addEventListener('touchstart', function(e){
clearTimeout(_time);
_firstX = e.touches[0].clientX;
// $swiperBox.addEventListener('touchmove', dragAnimation);
$swiperBox.addEventListener('touchend', draggable);
})
// 滑动动画
// function dragAnimation(e) {
// var moveX = e.touches[0].clientX - _firstX;
// $swiperInside.style.marginLeft = _swiperMarginLeft + moveX + 'px';
// }
// 滑动方法封装
function draggable(event) {
var _secondX = event.changedTouches[0].clientX;
var windowWidth = document.body.clientWidth;
if (_secondX - _firstX > windowWidth / 2){
pre();
} else if (_firstX - _secondX > windowWidth / 2) {
next();
} else {
$swiperInside.style.marginLeft = _swiperMarginLeft + 'px';
_time = setTime();
}
$swiperBox.removeEventListener('touchend', draggable);
// $swiperBox.removeEventListener('touchend', dragAnimation);
}
// 监听resize事件
window.addEventListener('resize', function(){
clearTimeout(_time);
_firstX;
_index = 0;
_swiperMarginLeft = 0;
$swiperInside.style.marginLeft = _swiperMarginLeft;
setTimeout(function(){
imgWidth = parseInt(window.getComputedStyle($img).getPropertyValue('width'));
_time = setTime();
}, 20);
}, false);
}
`