JS原生实现轮播图
前端新人的练习,希望能对同为小白的小伙伴有所帮助。
欢迎大佬们指正,欢迎大家讨论
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Rotation Chart</title>
<!-- js原生实现轮播图 -->
<!--
整体思路:
1.全局设置一个总定时器,控制自动轮播,该功能要返回一个定时器标志以便后续控制它
2.定时器终止:hover或按钮点击事件发生,清除当前定时器,轮播暂停
3.点击事件响应完毕(或没有点击事件在被响应)后、且鼠标已移出图片框,新建定时器继续轮播
4.点击事件响应:事件委托,统一处理点击事件
5.图片的移动由一个公共函数完成,被轮播和按钮响应事件共用
总的,需要:
一个图片移动函数
一个轮播函数,
一个开启轮播函数、一个结束轮播函数
需要处理的事件有:
鼠标hover事件、out事件,导航按钮点击事件
-->
<!-- 功能:
自动轮播、hover暂停轮播,
点击按钮切换图片(短时间的多次点击只以第一次点击为准,图片移动结束后才会响应新的点击)
均已实现,
可能还是有bug,欢迎大佬们指正,欢迎大家讨论
-->
<style>
* {
padding: 0;
margin: 0;
}
#imageList {
width: 620px;
height: 390px;
background-color: rgb(91, 100, 99);
margin: auto;
margin-top: 60px;
position: relative;
overflow: hidden;
}
/* 开启图片的绝对定位,方便后面JS将图片横向排布进行轮播 */
#images {
position: absolute;
}
li {
list-style: none;
padding: 0;
margin: 0;
float: left;
}
img {
width: 600px;
height: 370px;
margin: 10px;
}
/* 导航按钮栏位置:(不定宽高居中) */
#buttonBox {
position: absolute;
left: 50%;
top: 340px;
}
#buttons {
position: relative;
left: -50%;
}
#buttons li {
padding-right: 15px;
}
/* 导航按钮样式(选择了浮动,因为浮起来就是块元素了,方便调整其样式): */
#buttons a {
float: left;
width: 10px;
height: 10px;
/* opacity: 0.5; */
}
/* 按钮修改前后样式 */
.beforeChange {
background-color: rgb(240, 219, 29);
opacity: 0.5;
}
.afterChange {
background-color: rgb(255, 247, 220);
opacity: 0.8;
}
#buttons a:hover {
background-color: rgb(255, 255, 255);
}
</style>
</head>
<body>
<div id="imageList">
<ul id="images" class="infiniteRotation stranslateMove">
<!-- 这里的图片需要换成自己的路径 -->
<li class="img"><img src="img/1.jpg"/></li>
<li class="img"><img src="img/2.jpg"/></li>
<li class="img"><img src="img/3.jpg"/></li>
<li class="img"><img src="img/4.jpg"/></li>
<li class="img"><img src="img/5.jpg"/></li>
<li class="img"><img src="img/1.jpg"/></li>
</ul>
<div id="buttonBox">
<ul id="buttons">
<li><a href="javascript:;" class="beforeChange"></a></li>
<li><a href="javascript:;" class="beforeChange"></a></li>
<li><a href="javascript:;" class="beforeChange"></a></li>
<li><a href="javascript:;" class="beforeChange"></a></li>
<li><a href="javascript:;" class="beforeChange"></a></li>
</ul>
</div>
</div>
<script>
// 获取图片和导航钮对象组;
var imgs = document.getElementsByClassName("img");
var aS = document.getElementsByTagName("a");
var aLen = aS.length;
var iLen = imgs.length;
var buttons = document.getElementById("buttons");
var images = document.getElementById("images");
// 设置图片框整体大小
images.style.width = iLen * 620 + "px";
// 图片依次左右排列
for (let i = 0; i < iLen; i++) {
imgs[i].style.left = i * 620 + "px";
}
// 为按钮设置索引:
for (let i = 0; i < aLen; i++) {
aS[i].index = i;
}
// 设置点击事件后按钮样式的函数:
function setA(obj, lastObj) {
if (lastObj) {
lastObj.classList.remove("afterChange"); //将上一次按下的按钮恢复
}
obj.classList.add("afterChange"); //将此次按下的按钮点亮(点亮后的class覆盖了平常状态的class)
return obj;
}
setA(aS[0]); //第一个按钮在初始时应当时点亮状态
var lastClickA = aS[0]; //设置lastClickA变量接收上一次被点击的按钮对象
// 需要一个返回图片是否已到达指定位置的状态变量:
var arrive = true;
//为解决动画会产生大量不可控定时器的问题,引入以下函数,timeout可以实时关掉自己,避免出现多个定时器
// 以下是动画函数:
function move(nowLeft, target) {
var speed = 20;
if (nowLeft > target) {
speed = -speed;
}
var next = nowLeft + speed;
function littlemove(next) {
//移动的一小步函数,循环这个函数实现整体的移动
var timeout = setTimeout(function () {
images.style.left = next + "px";
next = next + speed;
clearTimeout(timeout);
if (next != target + speed) {
//当到达了图片目标位置就不再循环
littlemove(next);
}
if (next == target + speed) {
//到达目的位置才修改arrive变量值
arrive = true;
console.log(rotation);
//之前存在图片移动过程中鼠标移出图片框范围导致轮播重启被拦截、失效的问题
//这里添加一个判断,当总定时器不存在时意味着现在是非轮播状态,该状态下图片结束移动后重启定时器,继续
if (!rotation) {
start();
}
if (images.offsetLeft / -620 == iLen - 1) {
lastClickA = setA(aS[0], lastClickA);
} else {
lastClickA = setA(aS[images.offsetLeft / -620], lastClickA);
} //不管中间怎么按,最后还是会点亮显示的图片对应的按钮
}
}, 50);
}
if (arrive == true) {
arrive = false;
littlemove(next); //无点击事件
}
}
//自动轮播函数
function rotationSelf() {
nowLeft = images.offsetLeft;
if (nowLeft <= -(iLen - 1) * 620) {
images.style.left = 0;
lastClickA = setA(aS[0], lastClickA);
} else {
move(nowLeft, nowLeft - 620);
if (nowLeft == -(iLen - 2) * 620) {
lastClickA = setA(aS[0], lastClickA);
} else {
lastClickA = setA(aS[nowLeft / -620 + 1], lastClickA);
}
}
}
var rotation; //全局定时器声明,方便后续其它事件发生时对自动轮播功能进行处理(暂停再开启等)
function start() {
rotation = setInterval(function () {
//全局定时器,控制自动切换
if (images.offsetLeft % 620 == 0) {
//当图片移动到恰好的位置时才进行停顿
rotationSelf.call(images);
}
}, 1000);
}
function stop() {
//停止轮播函数
clearInterval(rotation);
}
//导航钮功能实现(这里不需要考虑重新开启定时器的问题,鼠标移到图片外时会自动开启轮播):
function guide(index) {
stop();
rotation = undefined;
lastClickA = setA(aS[index], lastClickA);
move(images.offsetLeft, index * -620);
}
// 下面是函数执行、事件响应处理:
start(); //初始状态应当是轮播开启的状态
//点击导航钮和鼠标hover时停止轮播,图片切换后以及鼠标移开后图片继续轮播
//先解决hover:
images.onmouseover = function () {
stop();
};
//这里需要考虑导航按钮触发的图片移动是否已经结束:
images.onmouseout = function () {
if (arrive) {
console.log(arrive);
start();
}
};
//事件委托(导航按钮点击事件响应)
buttons.onclick = function (event) {
let clickedA = event.target;
if (clickedA.nodeName == "A") {
//重复点击拦截:
//当一个按钮处于被选中状态下时,再次点击它或者点击其它按钮都是不起作用的,
//只有结束了当前移动才会开启新的响应:
if (arrive) {
guide(clickedA.index);
}
}
};
</script>
</body>
</html>