原生 JS 实现一个简单轮播图

在动手实现轮播图之前,我们先来明确一下要实现的效果。

  1. 默认自动轮播,每隔4秒切换一张图片
  2. 鼠标点击任一个小圆点即可切换到对应的图片
  3. 鼠标移入轮播区域时,两侧出现切换图片的按钮,点击按钮分别切换到上(下)一张图片

因此,轮播图可以分为三个主要部分,首先是我们的主体区域,用来展示图片;其次是图片导航区域,也就是上面说的小圆点;最后是两侧按钮,用于切换上一张、下一张图片。那么现在有几个问题需要考虑。

  1. 如何切换图片?也就是说如何在同一个区域显示不同的图片?
  2. 如何实现点击小圆点切换到对应的图片?如何实现点击左右两侧按钮切换前一张或后一张图片?

如何在同一区域显示不同图片?可以采用以下几种方法,亲测可用

  1. 图片区域放置一个 img 元素用于展示图片,改变 src 属性值切换图片
  2. 图片区域将所有需要展现的图片用相应数量的 img 元素展示,设置 css 样式隐藏 img 元素,opacity: 0 或 z-index: 0 均可。将需要展示的 img 样式改为 opacity: 1 或 z-index: 10 即可

如何实现点击小圆点切换对应图片呢?其实很简单,找到小圆点与图片的对应关系。因为图片和小圆点都可以视作数组,所以我的做法是将小圆点的索引位置跟图片的索引位置一一对应,比如第一个小圆点对应第一张图片,第二个小圆点对应第二张图片……以此类推,小圆点与图片之间的对应关系就建立起来啦。确定好对应关系之后,给小圆点绑定点击事件,当触发点击事件时,先将所有图片 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);
}

你可能感兴趣的:(JavaScript,javascript,前端,css,html)