【前端】原生 JS 实现轮播图

10/2/2022 JS

# 概述

# 实现原理

轮播图的实现:所有轮播图片横向排列,窗口范围内只显示一张图片,窗口外的图片隐藏,每次切换即移动一张图片的距离。
图片移动的方式:translate / position

  • 实现细节如下:
    • 图片自动播放
    • 点击中间圆点按钮,实现图片任意切换
    • 点击左右箭头按钮,实现图片左右切换
    • 图片的切换对应小圆点的样式变化,即每一个小圆点对应一张图片
    • 当鼠标在图片上、左箭头、右箭头时清除定时器,即图片不轮播
    • 当鼠标离开图片、左箭头、右箭头时开启定时器,即图片继续轮播
  • 轮播图切换的动画效果
    • 问题:当切换到最后一张图片后,再切换应该是第一张,依然需要同样的过渡效果,如何实现无缝切换?
    • 思路:在最后一张图片后再新增第一张图片,所有图片切换完毕之后,趁机切换回第一张(无过渡效果)重新开始
  • 实现的关键点
    • 全局声明 index 变量记录当前是第几张图片,这样无论是点击左右箭头还是小圆点都能继续下一步操作
    • 通过在轮播图的前面和后面放置跳板图片,实现图片的无缝播放

# HTML

<link rel="stylesheet" href="./demo.css" />

<div class="banner_container">
  <ul class="img_box">
    <li><img src="图片4" alt="" /></li>
    <li><img src="图片1" alt="" /></li>
    <li><img src="图片2" alt="" /></li>
    <li><img src="图片3" alt="" /></li>
    <li><img src="图片4" alt="" /></li>
    <li><img src="图片1" alt="" /></li>
  </ul>
  <ul class="sel_box">
    <li data-index="0"></li>
    <li data-index="1"></li>
    <li data-index="2"></li>
    <li data-index="3"></li>
  </ul>
  <div class="left_btn">&lt;</div>
  <div class="right_btn">&gt;</div>
</div>

<script src="./demo.js"></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# CSS

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

.banner_container {
  position: relative;
  margin: 100px;
  width: 400px;
  height: 250px;
  overflow: hidden;
}

ul.img_box {
  position: absolute;
  left: 0;
  top: 0;
  transform: translateX(-400px);
}

.img_box li {
  float: left;
  list-style: none;
}

.img_box li img {
  width: 400px;
}

.sel_box {
  position: absolute;
  bottom: 15px;
  left: 50%;
  transform: translateX(-50%);
}

.sel_box li {
  list-style: none;
  display: inline-block;
  width: 10px;
  height: 10px;
  background-color: pink;
  margin-right: 3px;
  border-radius: 5px;
  transition: all 0.4s;
}

.left_btn {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  width: 25px;
  height: 30px;
  background-color: #fff;
  line-height: 30px;
  padding-left: 3px;
  cursor: pointer;
}

.right_btn {
  position: absolute;
  top: 50%;
  left: 375px;
  transform: translateY(-50%);
  width: 25px;
  height: 30px;
  background-color: #fff;
  line-height: 30px;
  padding-left: 5px;
  cursor: pointer;
}

.sel_box .cur {
  background-color: red !important;
  transform: scale(1.3);
}
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

# JS

let imgBox = document.querySelector('.img_box');
let imgs = document.querySelectorAll('img');
let selBox = document.querySelector('.sel_box');
let sels = selBox.querySelectorAll('li');
let leftBtn = document.querySelector('.left_btn');
let rightBtn = document.querySelector('.right_btn');
let index = 0;
let timer = null;
let imgContainerW = imgBox.offsetWidth;
imgBox.style.width = imgContainerW * imgs.length + 'px';
imgBox.style.left = 0 + 'px';
sels[0].className = 'cur';

function swapImg() {
  imgBox.style.left = -index * imgContainerW + 'px';
  for (let i = 0; i < sels.length; i++) {
    sels[i].className = '';
  }
  list[index].className = 'cur';
}

function swapFormat() {
  index++;
  if (index >= 4) {
    index = 4;
    imgBox.style.transition = 'all, linear, 1s';
    imgBox.style.left = -index * imgContainerW + 'px';
    for (let i = 0; i < sels.length; i++) {
      sels[i].className = '';
    }
    list[0].className = 'cur';

    setTimeout(function () {
      index = 0;
      imgBox.style.transition = '';
      swapImg();
    }, 1500);
  } else {
    imgBox.style.transition = 'all, linear, 1.5s';
    swapImg();
  }
}

timer = setInterval(swapFormat, 3000);

rightBtn.addEventListener('click', function () {
  swapFormat();
});

leftBtn.addEventListener('click', function () {
  index--;
  if (index < 0) {
    index = -1;
    imgBox.style.transition = 'all, linear, 1.5s';
    imgBox.style.left = -index * imgContainerW + 'px';
    for (let i = 0; i < sels.length; i++) {
      sels[i].className = '';
    }
    sels[3].className = 'cur';

    setTimeout(function () {
      index = 3;
      imgBox.style.transition = '';
      swapImg();
    }, 1000);
  } else {
    imgBox.style.transition = 'all, linear, 1.5s';
    swapImg();
  }
});

imgBox.addEventListener('mouseover', function () {
  clearInterval(timer);
});

rightBtn.addEventListener('mouseover', function () {
  clearInterval(timer);
});

leftBtn.addEventListener('mouseover', function () {
  clearInterval(timer);
});

imgBox.addEventListener('mouseout', function () {
  timer = setInterval(swapFormat, 3000);
});

leftBtn.addEventListener('mouseout', function () {
  timer = setInterval(swapFormat, 3000);
});

rightBtn.addEventListener('mouseout', function () {
  timer = setInterval(swapFormat, 3000);
});
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

# 参考

Last Updated: 10/8/2022, 2:29:52 PM