原生JS实现轮播图
原生JS实现轮播图
js实现轮播图,我经历了一下几个步骤:
- 把静态界面写出来
- 添加切换上一张下一张的箭头(为了省事,直接用的
<
和>
…) - 通过调用setTimeOut,让图片动起来,实现轮播的效果
- 给每张图片绑定按钮,在鼠标移到相对应的数字时,就会切换到对应的图片
- 写博客总结一哈
先上效果图:
静态页面
静态页面的话没什么好说的,其实就是就是加了几张图片,然后修改了一下样式而已。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style> * { padding: 0px; margin: 0px; } ul { list-style-type: none; } li { float: left; } a { text-decoration: none; font-size: 50px; color: gray; position: absolute; top: 50%; } #prev { left: 0px; } #next { right: 0px; } .container { position: relative; margin: 10px auto; width: 375px; height: 525px; } .list { position: relative; width: 400px; height: 523px; border: 1px solid sienna; overflow: hidden; cursor: pointer; } .list ul { width:5000px; position: absolute; } .list ul li { display: inline; } .count { position: absolute; bottom: 10px; right: 0px; } .count li { float: left; text-align: center; font: 20px Arial; color: white; width: 20px; height: 20px; opacity: 0.7; margin-right: 10px; background: #f90; border-radius: 20px; cursor: pointer; } .count .current { opacity: 1; } </style>
</head>
<body>
<div class="container">
<div class="list">
<ul>
<li><img src="img/乔巴.jpg" alt="乔巴" width="400" height="523"></li>
<li><img src="img/路飞.jpg" alt="路飞" width="400" height="523"></li>
<li><img src="img/山治.jpg" alt="山治" width="400" height="523"></li>
<li><img src="img/索隆.jpg" alt="索隆" width="400" height="523"></li>
<li><img src="img/娜美.jpg" alt="娜美" width="400" height="523"></li>
<li><img src="img/罗宾.jpg" alt="罗宾" width="400" height="523"></li>
<li><img src="img/乔巴.jpg" alt="乔巴" width="400" height="523"></li>
<li><img src="img/路飞.jpg" alt="路飞" width="400" height="523"></li>
</ul>
<ul class="count">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
<a href="javascript:prev();" id="prev" class="arrow"><</a>
<a href="javascript:next();" id="next" class="arrow">></a>
</div>
</div>
<script src="js/carousel.js"></script>
</body>
</html>
需要注意的是,在图片列表中,第一张和最后一张图片重复添加了,这是为了实现图片之间的带动画效果的无缝切换,后面会讲。
添加箭头
我这里为了省事,直接使用的<
和>
,所以看起来可能不是那么的好看…
最初的计划只是让这两个箭头实现图片的切换,所以写起来就很简单了,只需要在点击箭头时,修改图片的位置就可以了,由于图片的位置使用的是绝对布局,所以位置的改变也是相当方便.
function prev() {
if(imgList.offsetLeft >= 0) {
return;
}
imgList.style.left = imgList.offsetLeft + 400 + 'px';
}
添加动画效果
最初的版本,只是让图片每隔2.5s移动一下,后面由于需要加上与图片关联的按钮,增加了传入的参数,来方便定位到目标图片的位置。
function movToRight(jmpNum) {
jmpNum = jmpNum ? jmpNum : 1;
if(imgList.offsetLeft <= -400*7) {
clearInterval(id);
imgList.style.left = "-400px";
id = setInterval(movToRight, 2500);
}
//console.log(imgList.offsetLeft);
for(let i = 0; i < 40*jmpNum; i++) {
setTimeout(function() {
imgList.style.left = imgList.offsetLeft - 10 + 'px';
//console.log(i);
},i*10/jmpNum);
}
}
最开始还有一个判断,当到达整个图片列表的尾部时,就会清除定时器,然后切换回第一张图片,重新开始轮播。第一次的轮播在页面初始化的时候就已经开始了。
当到达最后一张图片,如果直接切换回第一张图片,那么是没有动画效果的,所以为了实现这种动画效果,又在最后重复添加了第一张图片,这样就能无缝实现从最后一张到第一张的切换。第一张之前添加的那张图片也是这个原因。
将图片和按钮绑定
这个是为了实现图片的快速切换,当鼠标移到数字之上,就会切换到对应的图片。
其实就是向数字上添加了onmouseover事件,当鼠标移动到数字上的时候,判断当前图片和目标图片的距离,然后根据相对的位置,决定向左移还是向右移。
function bindNumWithImg() {
for(let i = 0; i < numList.length; i++) {
numList[i].onmouseover = function() {
this.className = "current";
console.log(this);
var currImg = -imgList.offsetLeft/400 - 1;
var diffVal = i - currImg;
if(diffVal >= 0) {
movToRight(diffVal);
} else {
movToLeft(-diffVal);
}
}
numList[i].onmouseleave = function() {
this.className = "";
}
}
}
总结
整个轮播图实现下来,代码并不多,不过80行左右,不过却让我对于js中的setTimeOut和setInterval这两个方法有了更深的理解。对于这两个方法,我原来用的并不多,或者说几乎没有用过,经过查阅一些资料,也借着这两个方法了解到了JS中的事件队列。JS的执行顺序是由浏览器进行控制的,在页面载入时,首先会对script标签下的代码,通常是一些变量和方法的声明,以及一些初始数据的处理。然后JS进程将等待更多代码的执行,进入空闲。进入空闲后,下一段代码会立即执行。下一段代码的位置就是事件处理队列。就比如说一个onclick方法,当点击那个绑定onclick的元素后,会立即把对应的方法加入到事件处理队列中去,但是不会立即执行,而是等到JS进程空闲时,才会执行代码。
setTimeOut也是这样的,只会在你设定的时间之后添加到事件处理队列中去,但并不一定会立即执行。
在使用setTimeOut时需要注意的是,传入的第一个参数,要么是一个方法,要么是一个代码段,注意,这个代码段是要加引号的,虽然在浏览器中不会报错,但是会立即执行。在node中会报错,指出传入参数不正确。
在实现的过程中,有一个问题困扰了我好久,就是实现的动画效果有些问题,在进行图片切换的时候,会有空白,额说不清楚,上图:
后面发现,由于某种原因,在当前图片之后的图片会到下一行,当然了,解决这个问题很简单,设置这一行的宽度很宽就行了,这里换行的原因是,由于是浮动元素,在排列时需要判断最右的边界,默认情况下,浮动元素是不能超过边界的,所以他就会自动的换行了。但是那些浮动的元素却可以到前面去,这是因为通过left改变了它的左边界。
最终效果图:
下面是完整的JS代码:
var list = document.getElementsByClassName("list")[0];
var imgList = list.getElementsByTagName('ul')[0];
var imgs = imgList.getElementsByTagName("li");
var numList = list.getElementsByClassName("count")[0].getElementsByTagName('li');
var id;//setInterval 的id
function init() {
imgList.style.left = "-400px";
list.onmouseover = function() {
clearInterval(id);
}
list.onmouseout = function() {
id = setInterval(movToRight, 2500);
}
autoPlay();
bindNumWithImg();
}
function bindNumWithImg() {
for(let i = 0; i < numList.length; i++) {
numList[i].onmouseover = function() {
this.className = "current";
console.log(this);
var currImg = -imgList.offsetLeft/400 - 1;
var diffVal = i - currImg;
if(diffVal >= 0) {
movToRight(diffVal);
} else {
movToLeft(-diffVal);
}
}
numList[i].onmouseleave = function() {
this.className = "";
}
}
}
function next() {
movToRight();
}
function prev() {
movToLeft();
}
//使得图片向左播放
function movToLeft(jmpNum) {
jmpNum = jmpNum ? jmpNum : 1;
if(imgList.offsetLeft >= 0) {
imgList.style.left = "-2400px";
}
for(let i = 0; i < 40 * jmpNum; i++) {
setTimeout(function() {
imgList.style.left = imgList.offsetLeft + 10 + 'px';
}, i*10/jmpNum);
}
}
//使得图片向右播放
function movToRight(jmpNum) {
jmpNum = jmpNum ? jmpNum : 1;
if(imgList.offsetLeft <= -400*7) {
clearInterval(id);
imgList.style.left = "-400px";
id = setInterval(movToRight, 2500);
}
//console.log(imgList.offsetLeft);
for(let i = 0; i < 40*jmpNum; i++) {
setTimeout(function() {
imgList.style.left = imgList.offsetLeft - 10 + 'px';
//console.log(i);
},i*10/jmpNum);
}
}
function autoPlay() {
id = setInterval(movToRight, 2500);
}
init();
其中的方法的设计可能有些不足,还请多多指点。
还没有评论,来说两句吧...