原生js实现轮播图
1、原理
- 一个装图片的大盒子,显示器内水平垂直居中,溢出的部分不显示,并且设置为相对定位
- ul>li>img,n个li,ul的大小要比大盒子的大小大出n倍,所有以百分比计算,并且绝对定位
- li浮动
- 设置两个按钮和底下原点的位置
- 让ul自己动,然后改变其left的大小
- 当图片切换的时候会有一个逐渐变慢的过程,那么我们自己创建一个动画的函数
- 在最后一张图片后边克隆第一个图片节点,插入到最后一个位置,用于过渡
- 当点击左边,如果是第一张图片则将其过渡到最后一张克隆的图片
- 当点击右边,如果是最后一张图片,则过渡到第一张图片的位置
- 当我们不点击,则默认向右切换图片
- 其实重点就是ul的移动、移动这个逐渐变慢的过程、以及第一张和最后一张图片的过渡,只要掌握了这个基本上做这个是没有问题的
2、源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>轮播图</title>
<style>
/* 清除浏览器自带的边距和不需要的样式 */
* {
padding: 0;
margin: 0;
list-style: none;
text-decoration: none;
}
/* 大盒子的样式 */
.box {
width: 500px;
height: 300px;
border: 1px solid #ccc;
margin: 100px auto;
padding: 5px;
}
/* 小盒子的样式 */
.inner {
width: 100%;
height: 100%;
/* 相对定位 */
position: relative;
/* 溢出的部分不显示 */
overflow: hidden;
}
/* 图片的样式 */
.inner img {
/*图片的大小和小盒子的大小相同 */
width: 500px;
height: 300px;
/* 图片居中对齐 */
vertical-align: top;
}
/* 无序列表的样式 */
.inner ul {
width: 1000%;
/* 绝对定位 */
position: absolute;
left: 0;
top: 0;
}
/* li的属性 */
.inner li {
/* 左浮动 */
float: left;
}
/* 有序列表的属性 */
ol {
position: absolute;
height: 20px;
right: 20px;
bottom: 5px;
text-align: center;
padding: 5px;
}
ol li {
display: inline-block;
width: 20px;
height: 20px;
line-height: 20px;
background-color: #fff;
margin: 5px;
cursor: pointer;
}
/* 第一个节点的背景颜色默认是红色 */
ol li:first-child {
background-color: red;
}
/* 箭头属性 */
#arr {
display: none;
}
#arr span {
width: 40px;
height: 40px;
position: absolute;
left: 5px;
top: 50%;
margin-top: -20px;
background-color: #fff;
cursor: pointer;
text-align: center;
font-weight: bold;
font-family: "黑体";
font-size: 30px;
color: #000000;
opacity: 0.5;
border: 1px solid #ffffff;
z-index: 999;
}
#arr #right {
right: 5px;
left: auto;
}
/* 鼠标经过里边的盒子则箭头出现 */
.inner:hover #arr {
display: block;
}
</style>
</head>
<body>
<!-- 外边框大盒子 -->
<div class="box">
<!-- 装图片的盒子 -->
<div class="inner">
<!-- 无序列表装载的图片集合 -->
<ul>
<li>
<a href="javascript:;">
<img src="./images/1.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/2.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/3.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/4.jpg" alt="">
</a>
</li>
<li>
<a href="javascript:;">
<img src="./images/5.jpg" alt="">
</a>
</li>
</ul>
<!-- 有序列表装载的下方索引按钮 -->
<ol class="bar">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
<!-- 图片上的方向箭按钮 -->
<div id="arr">
<span id="left">
<
</span>
<span id="right">
>
</span>
</div>
</div>
</div>
<script>
window.onload = function() {
// 准备工作:元素的获取
// 获取左右按钮
var left = document.querySelector("#arr #left");
var right = document.querySelector("#arr #right");
// 获取ul元素
var ul = document.querySelector("ul");
//获取ul下的所有li元素
var liList = document.querySelector("ul").children;
// 获取img元素的长度
var imgWidth = document.querySelector("img").clientWidth;
// 获取有序列表下的所有li
var ol = document.querySelector(".bar");
// 获取ol下的所有li节点
var olli = ol.children;
// 给ol中的每个li添加一个自定义属性
for (var i = 0; i < olli.length; i++) {
olli[i].setAttribute("index", i);
};
// 添加事件
// 使用事件委托给ol添加点击事件
ol.addEventListener("click", function(e) {
// 判断:如果绑定事件的元素与事件的触发者一样,则为ol元素
if (this == e.target) {
// 那么不执行
return;
};
// 调用设置颜色的函数
setbackgroundColor(olli, e.target);
// 获取触发该事件的元素对象的index属性
var index = e.target.getAttribute("index");
// 调用动画,默认向右
animation(ul, -imgWidth * index)
});
// 深拷贝第一个节点
var firstLi = liList[0].cloneNode(true);
// 添加到ul中
ul.append(firstLi);
// 计数器
var num = 0;
// 存储计时器的id
var time, timer = null;
// 左边注册点击事件
left.addEventListener("click", function() {
// 当num到第一张图片的索引时
if (num == 0) {
// 将num设置为最后一张图片的索引
num = liList.length - 1;
// 则此时改变ul距离左边的长度,其实就是切换到了最后一个图片的位置,从最后一个图片的位置往前过度
ul.style.left = num * -imgWidth + "px";
};
// 计数器递减
num--;
// 不断调用动画的函数
animation(ul, -imgWidth * num);
// 设置背景颜色
setbackgroundColor(olli, num);
});
// 右边注册点击事件
right.addEventListener("click", function() {
// 当计数器到第六张图片的索引时,但是还没还得及进入动画的时候(原本为5张,但是我们还克隆了第一张)
if (num == liList.length - 1) {
// 将num设置为第一张图片的索引
num = 0;
// 此时改变ul距离左边的距离,其实就是切换到第一张图片的位置,也就是从最后一张图片切换到第一张图片
ul.style.left = num + "px";
};
// 计数器递增
num++;
// 不断调用创建动画的函数
animation(ul, -imgWidth * num);
// 设置背景颜色
setbackgroundColor(olli, num == liList.length - 1 ? 0 : num);
});
// 计时器自调用right的点击事件
setInterval(function() {
right.click();
}, 2000)
// 封装设置下方按钮背景颜色的函数
function setbackgroundColor(olli, index) {
// 遍历ol下所有的li元素
for (var i = 0; i < olli.length; i++) {
// 先将所有背景颜色变白
olli[i].style.backgroundColor = "#fff";
};
// 目标元素改变背景颜色
olli[index].style.backgroundColor = "red";
};
//封装的动画函数 ,并接收一个元素对象和目标位置参数
function animation(obj, target, callback) {
// 每次进入该函数之前都清除之前的计时器
clearInterval(time);
//创建计时器
time = setInterval(function() {
// 获取left要走的长度,速度依次变慢
var step = (target - obj.offsetLeft) / 10;
// 如果每次的长度大于0则向上取整,否则向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// 如果ul的left==目标点
if (target == obj.offsetLeft) {
// 则停止计时器
clearInterval(time);
};
// 设置ul的left
obj.style.left = obj.offsetLeft + step + "px";
// 如果callback存在,则调用
if (callback) {
callback();
};
}, 20);
};
}
</script>
</body>
</html>
// 设置ul的left
obj.style.left = obj.offsetLeft + step + "px";
// 如果callback存在,则调用
if (callback) {
callback();
};
}, 20);
};
}
</script>
```