本文主要是实现轮播图并将其封装为一个插件

最终效果见如下链接


  1. 每张图对应底下的小圆点,点击小圆点会高亮并跳转到对应图片
  2. 左右两侧的按钮可以返回上一张图片或者进入下一张图片
  3. 当鼠标离开轮播图区域时,进入自动轮播模式

HTML部分

以下是轮播图的html框架,轮播图框中包含三部分内容,图片列表,前进后退按钮以及圆点列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="swiper">
<div class="preBtn"> < </div>
<div class="nxtBtn"> > </div>
<div class="imgList">
<img src="img/1.png" alt="" class="imgItem active">
<img src="img/2.png" alt="" class="imgItem">
<img src="img/3.png" alt="" class="imgItem">
<img src="img/4.png" alt="" class="imgItem">
<img src="img/5.png" alt="" class="imgItem">
</div>
<div class="circleList">
<div class="circle choose" data-id="0"></div>
<div class="circle" data-id="1"></div>
<div class="circle" data-id="2"></div>
<div class="circle" data-id="3"></div>
<div class="circle" data-id="4"></div>
</div>
</div>

CSS部分

然后我们来设置CSS部分

首先设置轮播框的css,我们选用金色作为其外框,定位选择relative,方便内部小圆点和前进后退按钮的absolute定位

1
2
3
4
5
6
7
.swiper {
height: 300px;
width: 500px;
border: gold solid 2px;
margin: 50px auto;
position: relative;
}

然后画上两个按钮,我们在html中设置<>作为两个按钮的符号

按钮用父元素swiper的长宽和自身长宽的一半来计算定位

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
.preBtn,
.nxtBtn {
width: 30px;
height: 50px;
background-color: rgba(97, 63, 0, 0.6);
position: absolute;
text-align: center;
line-height: 50px;
font-size: 30px;
color: rgba(255, 255, 255, 0.5);
z-index: 1;
/* 消除文字选中效果 */
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}

.preBtn {
top: calc(50% - 25px);
left: 5px;
}

.nxtBtn {
top: calc(50% - 25px);
left: calc(100% - 35px);
}

然后我们把圆点列表也定位上去,choose类用来给小圆点附加高亮状态,以下是我第一次实现时候的css代码,在五张图片的时候能够完成需求,但是图片数量变化的时候泛用性就不太好,我们在下文再来修改它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.circleList{
width: 100px;
height: 20px;
position: absolute;
top: 270px;
left: 400px;
}
.circle{
width: 12px;
height: 12px;
margin: 3px;
border-radius: 50%;
z-index: 2;
background-color: rgba(97, 63, 0, 0.6);
float: left;
}
.choose{
background-color: rgb(255, 115, 0);
}

最后我们将图片列表也定义上,这里在实现的时候也是有瑕疵的,用了固定高度和宽度,不太好封装

我们用active这个类给图片附加显示状态,不显示的图片设置为透明,为了让图片切换更加丝滑,我们给opacity这个属性设置1s的过渡时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.imgList {
height: 300px;
width: 500px;
position: absolute;
left: 0;
top: 0;
}

.imgItem {
height: 300px;
width: 500px;
position: absolute;
left: 0;
top: 0;
background-size: cover;
background-position: center;
opacity: 0;
transition: opacity 1s;
}

.active {
opacity: 1;
}

这样css部分就基本完成了

JS部分

首先我们获取所有的图片和小圆点,两个按钮的dom,同时设置一个index表示当前选中的小圆点(图片)

1
2
3
4
5
6
7
var imgsArr = document.querySelectorAll(".imgItem")
var circleArr = document.querySelectorAll(".circle")

var preBtn = document.querySelector(".preBtn")
var nxtBtn = document.querySelector(".nxtBtn")

var index = 0

对于图片的小圆点的切换,其实就是将原来的index的图片和圆点取消选中状态,给新的index的图片和圆点添加选中状态,所以这个取消和选中会在代码中反复使用,我们用两个函数来实现这个功能

1
2
3
4
5
6
7
8
var remove=function(){
imgsArr[index].classList.remove("active")
circleArr[index].classList.remove("choose")
}
var add=function(){
imgsArr[index].classList.add("active")
circleArr[index].classList.add("choose")
}

那么nxt和pre按钮点击事件的实现就会变得非常简单,以nxt按钮为例,代码如下

1
2
3
4
5
nxtBtn.addEventListener("click", function () {   
remove()
index = (index + 1) % imgsArr.length
add()
})

接下来实现小圆点点击的功能,同样可以利用这个remove和add

如果对每个小圆点添加点击事件的监听效率非常的低,因为点击事件可以向上冒泡,所以我们选择监听圆点列表,将事件委托给父级元素,通过target来判断点击了哪个小圆点,对图片和圆点状态做对应的切换即可

1
2
3
4
5
6
7
8
var circleList = document.querySelector(".circleList")
circleList.addEventListener("click", function(evt){
if(evt.target.className == "circle"){
remove()
index = parseInt(evt.target.dataset.id)
add()
}
})

最后来实现一个自动播放功能,我们用一个定时器来实现

1
2
3
var intervalId = setInterval(function () {
nxtBtn.click()
}, 3000)

我们希望在鼠标移入的时候停止自动播放,移出的时候开始自动播放

给swiper区域添加上对应的事件即可,鼠标移入时清除计时器,移开则重新设置计时器

1
2
3
4
5
6
7
8
9
var swiper = document.querySelector(".swiper")
swiper.onmouseenter = function () {
clearInterval(intervalId)
}
swiper.onmouseleave = function () {
intervalId = setInterval(function () {
nxtBtn.click()
}, 3000)
}

这样轮播图功能就大致实现了

我们发现在点击按钮的时候,如果点击过快,图片切换效果并不好,因此我们设置一个图片切换的时间间隔,让图片不至于过快速切换

1
2
3
4
5
6
7
8
9
10
11
12
13
// 用以限制按钮生效的频率
var canClick = true;
nxtBtn.addEventListener("click", function () {
if(canClick){
canClick = false
setTimeout(function(){
canClick = true
}, 500)
remove()
index = (index + 1) % imgsArr.length
add()
}
})

制成插件

对于经常使用的东西,我们可以将其制成插件,比如将轮播图功能制成一个插件,之后只要传入参数和图片就能生成一个新的轮播图

将轮播图制成插件需要能够根据不同的图片数量生成对应的圆点个数和图片dom数,同时原来html的元素要直接在js中生成

首先我们设置一下传入的参数,如下所示

1
2
3
4
5
6
7
var swiper = new Swiper({
name: "#swiper",
color: "gold",
imgs: ['img/1.png', 'img/2.png', 'img/3.png', 'img/4.png', 'img/5.png'],
height: 300,
width: 500
})

我们希望往Swiper函数中传入名字,边框颜色,图片和边框的长宽来生成个性化的轮播图

然后我们开始写这个Swiper函数,也就是我们的插件

1
2
3
function Swiper(options) {

}

首先,我们需要在Swiper里面生成dom元素 (也就是原来在html中写的内容)

先将swiper框设置出来,并用参数中的长宽和颜色修改css属性

1
2
3
4
5
var swiper = document.querySelector(options.name)
swiper.classList.add('swiper')
swiper.style.height = options.height + 'px'
swiper.style.width = options.width + 'px'
swiper.style.borderColor = options.color

然后我们设置图片列表和圆点列表的dom,之后根据图片数量往里面添加元素

1
2
3
4
5
6
7
8
9
10
// 设置circleList和imgList
var index = 0
var imgList = document.createElement('div')
var circleList = document.createElement("div")
imgList.className = "imgList"
circleList.className = "circleList"

// 将dom添加到swiper
swiper.appendChild(imgList)
swiper.appendChild(circleList)

添加图片dom和圆点部分如下

1
2
3
4
5
6
7
8
9
10
11
// 对每张图片生成对应dom和小圆点
options.imgs.forEach(function (item, i) {
let imgItem = document.createElement('img')
imgItem.src = item
imgItem.className = i == index ? 'imgItem active' : 'imgItem'
let circle = document.createElement('div');
circle.className = i == index ? "circle choose" : "circle"
circle.setAttribute('data-id', i)
imgList.appendChild(imgItem)
circleList.appendChild(circle)
})

然后设置按钮

1
2
3
4
5
6
7
8
9
10
11
// 按钮
var preBtn = document.createElement("div")
preBtn.className = "preBtn"
preBtn.innerText = "<"
var nxtBtn = document.createElement("div")
nxtBtn.className = "nxtBtn"
nxtBtn.innerText = ">"

// 将按钮添加到swiper
swiper.appendChild(nxtBtn)
swiper.appendChild(preBtn)

之后的操作就和之前js实现的部分一致,参照上文js实现部分即可

然后是将css添加到插件中来,我们可以要求插件使用者将css引入html文档,当然更方便的是将css直接添加到js中,我们只要生成一个style dom,添加到body元素中即可

1
2
3
4
var style = document.createElement("style")
// 两个反引号
style.innerHTML = `[填入style部分]`
document.body.appendChild(style)

这里我们用两个反引号 (键盘右上角那个) 来引入样式,可以将多行放入两个反引号之中,直接从css中复制过来即可

这里的css需要做一下修改,更好地适配

首先是圆点列表的css属性,为了让图片数量变化的时候圆点列表能够不出问题,我们改变一下圆点排布方式

首先float:left肯定是不行的,因为这得设置圆点开始的位置,当圆点数量增加或者减少时看起来会特别奇怪,float:right则会使得圆点的编号是从右向左的,处理起来十分麻烦,所以我们放弃浮动布局,采用弹性布局,用flex-end来使得小圆点靠右侧

1
2
3
4
5
6
7
8
9
.circleList{
width: 98%;
height: 20px;
position: absolute;
top: 90%;
left: 0px;
display: flex;
justify-content: flex-end;
}

同时将imgListimgItem长宽改为100%,使得其能随着swiper参数的变化而变化

最后我们来检验一下我们的插件,插入七张图,边框颜色设置为pink

就可以看到插件的效果

宽高和边框颜色都如我们所料变化了

插件完成

我已将插件上传至github,有学习或使用需要可以下载,有任何问题欢迎评论