在动手实现轮播图之前,我们先来明确一下要实现的效果。
因此,轮播图可以分为三个主要部分,首先是我们的主体区域,用来展示图片;其次是图片导航区域,也就是上面说的小圆点;最后是两侧按钮,用于切换上一张、下一张图片。那么现在有几个问题需要考虑。
如何在同一区域显示不同图片?可以采用以下几种方法,亲测可用
如何实现点击小圆点切换对应图片呢?其实很简单,找到小圆点与图片的对应关系。因为图片和小圆点都可以视作数组,所以我的做法是将小圆点的索引位置跟图片的索引位置一一对应,比如第一个小圆点对应第一张图片,第二个小圆点对应第二张图片……以此类推,小圆点与图片之间的对应关系就建立起来啦。确定好对应关系之后,给小圆点绑定点击事件,当触发点击事件时,先将所有图片 opacity 重置为 0,然后将对应图片的 opacity 设为 1 即可。切换上(下)一张图片也是类似的,给左右按钮绑定点击事件,触发事件时先将所有图片 opacity 置 0,再将当前图片的上(下)一张图片显示出来。其实本质上就是要显示图片数组中指定位置的那张图片
,所以我们只要知道需要显示的那张图片在图片数组中的位置
就好啦。下面我们开始一步一步地用代码来实现。
先将页面元素绘制出来,代码如下。
<div id="area">
<div id="imgs">
<img src="../img/ts01.jpg" class="active">
<img src="../img/ts02.jpg">
<img src="../img/ts03.jpg">
<img src="../img/ts04.jpg">
<img src="../img/ts05.jpg">
div>
<ol id="items">ol>
<div id="direction">
<div id="left"><div>
<div id="right">>div>
div>
div>
接下来用 css 样式绘制轮播图样式,这里将图片显示、小圆圈高亮以及左右两侧按钮显示的样式单独写出来了,用 active 类来标识。也就是说只要给需要显示的图片加上类 active ,要隐藏的图片删掉 active 类即可,小圆圈的高亮和左右按钮的显示与隐藏也同理。代码如下。
* {
margin: 0;
padding: 0;
list-style: none;
}
#area {
width: 600px;
height: 400px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
#imgs {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
#imgs > img {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: all .3s;
}
/* 当前显示的图片 */
#imgs > img.active {
opacity: 1;
}
/* 小圆圈 */
#items {
width: 200px;
height: 30px;
line-height: 30px;
text-align: center;
position: absolute;
bottom: 0;
right: 0;
}
#items > li {
display: inline-block;
cursor: pointer;
width: 12px;
height: 12px;
margin: 0 5px;
border-radius: 50%;
border: 1px solid rgba(255, 255, 255, 0.9);
}
/* 当前高亮的小圆圈 */
#items > li.active {
background-color: rgba(255, 255, 255, 0.9);
}
/* 左右箭头 */
#direction {
width: 100%;
height: 100%;
display: none;
}
/* 显示左右箭头 */
#direction.active {
display: block;
}
#direction > div {
width: 25px;
height: 50px;
line-height: 50px;
font-size: 18px;
text-align: center;
cursor: pointer;
/* 垂直居中 */
position: absolute;
top: 50%;
transform: translateY(-50%);
color: rgba(255, 255, 255, 0.9);
background-color: rgba(0, 0, 0, 0.5);
}
#direction > #left {
left: 0;
}
#direction > #right {
right: 0;
}
接下来就是重头戏了,js 部分的代码,咱们分步骤来。首先要获取我们后续需要用到的元素。
var nowIndex = 0; // 当前图片的索引,默认第一张图片
var box = document.getElementById("area"); // 获取整个轮播图区域
var imgList = document.getElementById("imgs").children; // 获取图片列表
var olList = document.getElementById("items"); // 获取小圆圈列表
var btnBox = document.getElementById("direction"); // 获取包含左右两侧按钮的区域
现在我们给轮播图加上小圆圈,注意有小技巧,我们可以利用文档碎片,先将所有待添加 li 元素放到一个文档碎片中,待所有 li 元素添加完成后,一次性添加到真正的 DOM 中,这样有效地减少了对真实 DOM 的操作。代码如下。
function addList(){
// 根据图片数量,生成对应数量的小圆圈
var dom = document.createDocumentFragment();
var len = imgList.length;
for (var i = 0; i < len; i++) {
var olLi = document.createElement("li");
// 默认第一个小圆圈高亮
if (i == 0) {
olLi.className = "active";
}
// 给每个 li 元素添加 index 属性,表示当前小圆圈的索引
olLi.index = i;
dom.appendChild(olLi);
}
olList.appendChild(dom);
}
// 调用函数,生成小圆圈
addList();
// 获取小圆圈列表,以备后面使用
var list = olList.children;
现在小圆圈都已经生成了,接下来就给它们绑定事件,点击任意小圆圈显示对应的图片。注意,这里我们的小圆圈是动态生成的,怎么给动态生成的元素绑定事件呢?一个方法是在生成元素的同时,给元素绑定事件,还有一种更好的做法就是利用事件委托,给父元素绑定事件。判断当前点击的是第几个小圆圈就显示第几张图片,我选择用事件委托的方式,代码如下。
olList.addEventListener("click", function(e){
// e.target 就是当前点击的元素,直接获取它的 index 属性就知道是第几个小圆圈啦,也是要显示的第几张图片
nowIndex = e.target.index;
showThisImg(nowIndex);
});
其实经过上面的操作,图片与小圆圈的对应关系基本上就确定了,已经获取到了要显示的图片的索引,那么接下来我们来完成显示指定图片的功能,将其封装成函数,传入图片的索引值即可,代码如下。
function showThisImg(thisIndex){
var len = imgList.length;
for (var i = 0; i < len; i++) {
// 给指定图片应用 active 样式,其它不需要显示的图片则删除 active 类
if (i == thisIndex && imgList[i].className == "") {
imgList[i].className = "active";
list[i].className = "active";
} else if (i != thisIndex && imgList[i].className != "") {
imgList[i].className = "";
list[i].className = "";
}
}
}
既然显示对应图片的功能做好了,也就意味着自动轮播也可以完成啦。自动轮播其实就是定时更改当前显示的图片,那么只需要定时修改当前图片的索引即可,代码如下。
var interval = setInterval(autoChange, 4000);
function autoChange(){
nowIndex++;
// 所有图片都已经显示过一遍,又从第一张开始
if (nowIndex >= imgList.length) {
nowIndex = 0;
}
showThisImg(nowIndex);
}
自动轮播也已经完成了,接下来继续完成左右两侧按钮切换图片的功能。鼠标移入移出分别触发 mouseenter 和 mouseleave 事件,鼠标移入轮播区域时,清空定时器即可取消自动轮播,且将按钮区域的 display 属性设为 block 将其显示出来,移出则重新定时,并将 display 设为 none 隐藏。给左右按钮绑定点击事件我也利用事件委托的方式,代码如下。
// 鼠标移入轮播图区域时,显示两边的按钮,且停止自动轮播
box.addEventListener("mouseenter", function(){
btnBox.className = "active";
clearInterval(interval);
interval = null;
});
// 鼠标离开轮播图区域时,隐藏两边的按钮,再次开启自动轮播
box.addEventListener("mouseleave", function(){
btnBox.className = "";
interval = setInterval(autoChange, 4000);
});
btnBox.addEventListener("click", function(e){
if (e.target.id == "left") {
// 点击的是左侧按钮,需要显示上一张图片,nowIndex 减一。若当前图片已经是第一张则显示最后一张
nowIndex = nowIndex == 0 ? imgList.length - 1 : nowIndex - 1;
} else if (e.target.id == "right") {
// 点击的是右侧按钮,需要显示下一张图片,nowIndex 加一。若当前图片已经是最后一张则从第一张开始
nowIndex = nowIndex == imgList.length - 1 ? 0 : nowIndex + 1;
}
// 显示 nowIndex 对应的图片
showThisImg(nowIndex);
});
至此,一个简单的轮播图就完成啦!来看看效果图(Taylor 美图来袭!)
JS 部分的整体代码如下。
var nowIndex = 0;
var imgList = document.getElementById("imgs").children;
var olList = document.getElementById("items");
var btnBox = document.getElementById("direction");
var box = document.getElementById("area");
var interval = setInterval(autoChange, 4000);
// 动态生成小圆圈,利用事件委托,给父元素ol绑定事件,判断当前点击的是第几个小圆圈,则显示对应的第几张图片
addList();
var list = olList.children;
olList.addEventListener("click", function(e){
nowIndex = e.target.index;
showThisImg(nowIndex);
});
// 鼠标移入轮播图区域时,显示两边的按钮,且停止自动轮播
box.addEventListener("mouseenter", function(){
btnBox.className = "active";
clearInterval(interval);
interval = null;
});
// 鼠标移出轮播图区域时,隐藏两边的按钮,开启自动轮播
box.addEventListener("mouseleave", function(){
btnBox.className = "";
interval = setInterval(autoChange, 4000);
});
// 给按钮绑定事件,点击左侧按钮显示上一张,点击右侧按钮显示下一张
btnBox.addEventListener("click", function(e){
if (e.target.id == "left") {
nowIndex = nowIndex == 0 ? imgList.length - 1 : nowIndex - 1;
} else if (e.target.id == "right") {
nowIndex = nowIndex == imgList.length - 1 ? 0 : nowIndex + 1;
}
showThisImg(nowIndex);
});
function addList(){
// 根据图片数量,生成对应数量的小圆圈
var dom = document.createDocumentFragment();
var len = imgList.length;
for (var i = 0; i < len; i++) {
var olLi = document.createElement("li");
if (i == 0) {
olLi.className = "active";
}
olLi.index = i;
dom.appendChild(olLi);
}
olList.appendChild(dom);
}
function showThisImg(thisIndex){
var len = imgList.length;
for (var i = 0; i < len; i++) {
// 修改图片样式
if (i == thisIndex && imgList[i].className == "") {
imgList[i].className = "active";
list[i].className = "active";
} else if (i != thisIndex && imgList[i].className != "") {
imgList[i].className = "";
list[i].className = "";
}
}
}
function autoChange(){
nowIndex++;
if (nowIndex >= imgList.length) {
nowIndex = 0;
}
showThisImg(nowIndex);
}