js定时器实现自动轮播图
程序员文章站
2024-03-22 00:02:28
...
自动轮播的效果图如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
ul,
ol {
list-style: none;
}
a {
text-decoration: none;
color: #333;
}
.box {
width: 300px;
height: 300px;
margin: 40px 300px;
border: 2px solid blue;
position: relative;
overflow: hidden;
}
.clear::after {
content: "";
display: block;
clear: both;
}
.box ul {
height: 100%;
font-size: 30px;
/* 设置定位是因为后面复制li加到最前面时要显示的是第二张 */
position: absolute;
left: 0;
top: 0;
}
.box ul li {
width: 300px;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
float: left;
}
.box ol {
width: 100%;
display: flex;
justify-content: space-evenly;
align-items: center;
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
.box ol li {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid #000;
margin: 0 15px;
cursor: pointer;
}
.box ol li.active {
background-color: rebeccapurple;
}
.box div {
width: 100%;
height: 50px;
position: absolute;
top: 50%;
transform: translateY(-50%);
display: flex;
justify-content: space-between;
align-items: center;
}
.box div a {
font-size: 40px;
color: #000;
font-weight: bold;
}
</style>
</head>
<body>
<div class="box">
<ul class="clear">
<li style="background: hotpink;">图片一</li>
<li style="background: greenyellow;">图片二</li>
<li style="background: rosybrown;">图片三</li>
<li style="background: burlywood;">图片四</li>
<li style="background: seagreen;">图片五</li>
<!-- <li style="background: hotpink;">图片六</li>
<li style="background: greenyellow;">图片七</li>
<li style="background: rosybrown;">图片八</li>
<li style="background: burlywood;">图片九</li>
<li style="background: seagreen;">图片十</li> -->
</ul>
<ol></ol>
<!-- 此处还没实现,有需要可以评论联系我一起讨论 -->
<div>
<a href="JavaScript:;"> < </a>
<a href="JavaScript:;"> > </a>
</div>
</div>
<script src="./utils.js"></script>
<script>
var oBox = document.querySelector(".box");
var oUl = document.querySelector("ul");
var oUllis = document.querySelectorAll("ul li");// 一开始的li的长度,不包括后面复制加入的两个li
var oOl = document.querySelector("ol");
var LiWidth = parseInt(window.getComputedStyle(oUllis[0]).width);// 获取图片的宽度
var index = 1; // 显示当前图片的位置,用来计算移动多少
var time = 0; // 保存自动播放中定时器编号,用于后面清除定时器
// 动态生成小圆圈函数
setLi();
// 复制第一个图片和最后一个图片的函数
copyLi();
// 得到小圆圈,用于下面改变样式
var oOllis = document.querySelectorAll("ol li");
// 自动播放函数
autoLoop();
// 鼠标移上去停止移动,清除定时器,拿开就重新执行自动播放函数
stopLoop();
</script>
</body>
</html>
utils.js文件中代码如下:
/*
1.动态生成点击用的圆圈li,因为多少图片不固定,所以需要根据图片数量动态生成
2.形成轮播的视觉,复制最后一个放在第一位,然后复制第一个放在最后一位
3.移动函数,设置目标位置,通过不断更新当前位置与目标位置作比较,到达就停止,
也可以设置其他属性(例如宽)的目标值,变化完成就停止
4.写个自动播放函数通过控制移动函数动作,移动函数有个参数是回调函数。
5.回调函数,移动结束后会执行回调函数,用来在移动结束后瞬间回到第一张图片
6.停止播放函数,用鼠标控制播放函数,移上去停止播放,移走鼠标后继续执行播放函数
*/
// 动态生成小圆圈函数
function setLi() {
var str = "";
oUllis.forEach(function (v, key) {
if (key === 0) {
str += `<li class='active'></li>`;
}
else {
str += `<li></li>`;
}
});
oOl.innerHTML = str;
}
// 复制第一个图片和最后一个图片的函数
function copyLi() {
var liFirst = oUllis[0];
var liLast = oUllis[oUllis.length - 1];
// 先克隆第一个和最后一张图片,然后加入到ul中最前面和最后面
var first = liFirst.cloneNode(true);
var last = liLast.cloneNode(true);
oUl.appendChild(first);
oUl.insertBefore(last, liFirst);
// 设置ul宽度,使其不会换行排列
oUl.style.width = ((oUllis.length + 2) * LiWidth) + "px";
// 改变ul的初始位置,使其显示的是第一张图片
oUl.style.left = -LiWidth + 'px';
}
// 传入的参数是标签对象和存放样式的一个对象,对象存储的是运动的目标值,最后是个回调函数
function move(elem, obj, callBack) {
// 存储定时器编号
let time = {};
// 循环遍历对象,有几个键值对就创建几个不同的定时器用来执行不同的样式变化
for (let type in obj) {
let oldVal = 0;
// 透明度是小数,先转换一下
if (type === "opacity") {
// 因为有小数,小数判断相等时有误差,下面的判断难以执行,所以特殊转换
oldVal = parseFloat(window.getComputedStyle(elem)[type]) * 100;
}
else {
oldVal = parseInt(window.getComputedStyle(elem)[type]);
}
// 对象的键值对分别代表样式属性和定时器标号
time[type] = setInterval(function () {
// 分五次运动到目标位置,分母数值越大运动越慢
let val = (obj[type] - oldVal) / 10;
// 设置取整,整数就向上取整,比如0.9直接取1,-0.9取-1,否则下面判断无法等于
val = val > 0 ? Math.ceil(val) : Math.floor(val);
// 更新位置
oldVal += val;
// console.log(oldVal);
// 进行判断属性是不是透明度,因为给的是乘以100后的值,需要除以100,写入标签样式中
if (type === "opacity") {
elem.style[type] = oldVal / 100;
// console.log(oldVal);
}
else {
elem.style[type] = `${oldVal}px`;
}
if (oldVal == obj[type]) {
clearInterval(time[type]);
// delete 操作符用于删除对象的某个属性;如果没有指向这个属性的引用,那它最终会被释放
delete (time[type]);
}
if (Object.keys(time) == 0) {
// 运动停止后执行的函数
callBack();
}
}, 100);
}
}
// 自动播放函数
function autoLoop() {
time = setInterval(function () {
// 加一次就是需要加载下一张图片了
index++;
move(oUl, { left: -index * LiWidth }, moveEnd);
// 因为小圆圈的数量比图片少一个,就是复制的那个,所以要先判断长度,否则会出错,
// 因为最后一个对应的小圆圈是第一个,而不是减1,
if (index == oOllis.length + 1) {
oOllis[oOllis.length - 1].className = "";
oOllis[0].className = "active";
}
else {
// 因为index是从1开始,所以要减1,减2,清除上个标签的样式,给现在这个标签加上样式
oOllis[index - 2].className = "";
oOllis[index - 1].className = "active";
}
}, 4000); // 时间至少四秒,否则会出现闪烁,执行出问题
}
// 移动结束后要瞬间跑到第一张图片开始那
function moveEnd() {
if (index == oUllis.length + 1) {
index = 1;
oUl.style.left = -index * LiWidth + 'px';
}
}
// 鼠标移上去停止移动,清除定时器,拿开就重新执行自动播放函数
function stopLoop() {
oBox.addEventListener("mouseover", function () {
clearInterval(time);
});
oBox.addEventListener("mouseout", function () {
autoLoop();
});
}
此种方法写的自动轮播图大部分都是js自动生成,可扩展性强,随便加入图片可不用改变css样式。
有需要实现点击的轮播图可以参考js实现点击轮播图,有需要扩展的或者不懂的可以跟我一起讨论。