轮播图的思想
轮播图的思想,最简单的描述就是通过修改不可见框的left值,来实现滑动播放的效果。
这篇文章从三大步骤来写一下轮播图的实现。
(一)完成轮播图界面
(二)完成点击按钮切换图片的功能
(三)使用定时器完成轮播图的功能
完成轮播图的界面
不可见框
不可见框中应该把图片连成横向一排,像胶卷一样。
<body>
<!-- #outer为不可见框部分 将所有的图片连成一排 -->
<div id = "outer">
<ul id = "imgList">
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/2.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/3.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/4.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/5.jpg"/ style="width:500px;height:333px"></li>
</ul>
</div>
</body>
在body中,我们放入了五张照片,但现在的图片是成列显示的(li为块级元素)。我们进一步用CSS来进行样式的修改。
<style type="text/css">
*
{
margin:0;
padding:0;
}
/*设置outer可见框的样式*/
#outer
{
width:520px;
height: 333px;
margin: 50px auto;
background-color: yellowgreen;
padding:10px 0;
}
/*设置不可见框的样式 将图片排成一行*/
#imgList
{
list-style: none; /*去除li自带的小圆点*/
width:2600px;/*共有5张照片和margin10px--写死不好 后面用js动态修改*/
}
#imgList li
{
float:left;/*设置float后图片并没有成一行排列,原因是ul的大小被outer限制住了。*/
margin:0 10px;
}
</style>
进行设置后的页面如下所示:
这时我们存在一个问题,如果我们希望图片的数量是能够动态改变的话。在CSS样式中直接写死ul的宽度是不合理的。
这时我们可以借助js来实现动态修改ul的宽度
window.onload = function()
{
//设置imgList的宽度
var imgList = document.getElementById("imgList");
var imgArr = document.getElementsByTagName("img");
imgList.style.width = 520*imgArr.length+"px";
}
ul不可见框的左移
想要让图片实现轮播的效果,想象一下一个人将红色框往左拉,图片是不是就动起来了~想要实现这个效果,我们就需要left属性的帮助了!
#outer
{
width:520px;
height: 333px;
margin: 50px auto;
background-color: yellowgreen;
padding:10px 0;
position:relative;/*让ul能相对于可见框来偏移*/
}
/*设置不可见框的样式 将图片排成一行*/
#imgList
{
list-style: none; /*去除li自带的小圆点*/
/*width:2600px;*/
/*共有5张照片和margin10px*/
position:absolute;/*开启绝对定位,并为父元素开启相对定位*/
left:-100px;
}
我们先来看看设置了-100px偏移量的效果是怎样的。
效果很显而易见了吧~如果我们想要让第二张图片显示在可见框上,应该设置-520px的偏移量。具体的原理我想看到这儿应该就懂了。那么就可以让不可见框真正的不可见了。为outer设置overflow:hidden;属性。
创建导航按钮
对于轮播图来讲,都会有一些导航按钮来实现切换图片的功能。我们先在界面上将导航按钮创建出来~
其中html结构为:
<div id = "outer">
<ul id = "imgList">
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/2.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/3.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/4.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/5.jpg"/ style="width:500px;height:333px"></li>
</ul>
<!-- 创建导航按钮 -->
<div id="navDiv">
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
</div>
</div>
新增的css样式为:
#navDiv
{
position: absolute;/*设置导航栏所在的位置*/
bottom:15px;
left: 197px;
}
#navDiv a
{
float:left;/*a为内联元素,应设置浮动*/
width: 15px;
height: 15px;
background-color: red;
margin: 0 5px;
opacity: 0.5;/*设置半透明*/
}
#navDiv a:hover
{
background-color: black;/*设置鼠标移入效果*/
}
页面的显示效果如下:
这时又存在一个问题了,如果我们希望图片的多少是动态的变化的话,我们也希望这个导航块的数量也是可以动态变化的。js又出来救场了~
//设置导航按钮居中
var imgDiv = document.getElementById("navDiv");
var outer = document.getElementById("outer");
navDiv.style.left=(outer.offsetWidth - navDiv.offsetWidth)/2+"px";
还有一个问题就是我们默认进入时显示的是第一张图片,这时第一个导航块应该是黑色的。这也需要js来救场~
var index = 0;//设置图片的索引 默认第一张
var allA = document.getElementsByTagName("a");
allA[index].style.backgroundColor = "black";
到了这一步,(一)完成轮播图界面 算是完成了。下面是到这一步的所有代码。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>轮播图</title>
<style type="text/css">
*
{
margin:0;
padding:0;
}
/*设置outer可见框的样式*/
#outer
{
width:520px;
height: 333px;
margin: 50px auto;
background-color: yellowgreen;
padding:10px 0;
position:relative;/*让ul能相对于可见框来偏移*/
overflow: hidden;/*让不可见框真正的不可见*/
}
/*设置不可见框的样式 将图片排成一行*/
#imgList
{
list-style: none; /*去除li自带的小圆点*/
/*width:2600px;*//*共有5张照片和margin10px*/
position:absolute;/*开启绝对定位,并为父元素开启相对定位*/
left:-520px;/*每向左移动520px,可见框中就会显示下一张图片*/
}
#imgList li
{
float:left;/*设置float后图片并没有成一行排列,原因是ul的大小被outer限制住了。*/
margin:0 10px;
}
#navDiv
{
position: absolute;/*设置导航栏所在的位置*/
bottom:15px;
/*left: 197px;*//*通过js来动态设置居中*/
}
#navDiv a
{
float:left;/*a为内联元素,应设置浮动*/
width: 15px;
height: 15px;
background-color: red;
margin: 0 5px;
opacity: 0.5;/*设置半透明*/
}
#navDiv a:hover
{
background-color: black;/*设置鼠标移入效果*/
}
</style>
<script type="text/javascript">
window.onload = function()
{
//设置imgList的宽度
var imgList = document.getElementById("imgList");
var imgArr = document.getElementsByTagName("img");
imgList.style.width = 520*imgArr.length+"px";
//设置导航按钮居中
var imgDiv = document.getElementById("navDiv");
var outer = document.getElementById("outer");
navDiv.style.left=(outer.offsetWidth - navDiv.offsetWidth)/2+"px";
var index = 0;//设置图片的索引 默认第一张
var allA = document.getElementsByTagName("a");
allA[index].style.backgroundColor = "black";
}
</script>
</head>
<body>
<!-- #outer为可见框部分-->
<div id = "outer">
<ul id = "imgList">
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/2.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/3.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/4.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/5.jpg"/ style="width:500px;height:333px"></li>
</ul>
<!-- 创建导航按钮 -->
<div id="navDiv">
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
</div>
</div>
</body>
</html>
完成点击按钮切换图片的功能
实现点击按钮切换照片
想要实现这个功能,我们的重点在于:
(1)知道我们点击的按钮代表着第几张照片。
(2)将不可见框移动相应的偏移量,使得可见框中可以看到想要看到的图片。
在js中,添加这样一段代码。
for(var i = 0; i<allA.length;i++)
{
//为每一个超链接都添加一个num属性,记录下点击第几张图片。
allA[i].num = i;
allA[i].onclick=function()
{
index = this.num;
//根据index设置偏移量,可以让可见框中显示图片。
imgList.style.left = -520*index+"px"
}
}
这时已经可以实现点击按钮切换照片了。但是仍然是有些问题的,如:
*选中导航块后,该导航块的颜色应该改变。
选中图片,导航块颜色改变
我们定义了一个方法来实现这个功能,在设置所选导航块颜色为黑色前,应该遍历所有的导航块让其恢复红色。
function setA(){
//遍历全部的导航块,让其变红
for(var i = 0; i<allA.length; i++)
{
allA[i].style.backgroundColor="";
//不能直接设置为红色,因为内联样式优先级太高,会使hover失效。
}
//将选中的导航块变黑
allA[index].style.backgroundColor="black";
}
再在上面的单击响应事件中调用这个方法即可。
切换时添加动画效果
我们定义了一个move函数,用来实现图片以某个速度滑动的效果。将这个函数放到tool.js中,再引入。
function move(obj,attr,target,speed,callback)
{
//在每次开启定时器之前,关闭掉之前的定时器。
clearInterval(obj.timer);
//获取当前的left值
var current = parseInt(getStyle(obj,attr));
/*
判断速度的正负,如果是从0->800移动,speed为正;
如果是从800->0移动,speed为负。
*/
if(current > target)
{
speed = -speed;
}
//开启一个定时器,用来执行动画效果
//向执行动画的对象中添加一个timer属性,用来保存它自己的定时器的标识。
obj.timer = setInterval(function()
{
//获取box1的原来的left值
var oldvalue = parseInt(getStyle(obj,attr));
//在oldvalue的基础上增加。
var newvalue = oldvalue + speed;
//向左移动时,需要判断newvalue是否小于target
//向右移动时,需要判断newvalue是否大于target
if((speed<0 && newvalue < target) || (speed>0 && newvalue > target))
{
newvalue = target;
}
//attr为变量,需要用[]的形式而不能是.的形式
obj.style[attr] = newvalue + "px";
//当元素移动到800px时停止执行动画
if(newvalue == target)
{
clearInterval(obj.timer);
//动画执行完毕,调用回调函数;
callback && callback();
}
},30);
}
修改js中的代码,调用move函数实现缓慢切换图片
这时,完整的页面代码是这样的:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>轮播图</title>
<style type="text/css">
*
{
margin:0;
padding:0;
}
/*设置outer可见框的样式*/
#outer
{
width:520px;
height: 333px;
margin: 50px auto;
background-color: yellowgreen;
padding:10px 0;
position:relative;/*让ul能相对于可见框来偏移*/
overflow: hidden;/*让不可见框真正的不可见*/
}
/*设置不可见框的样式 将图片排成一行*/
#imgList
{
list-style: none; /*去除li自带的小圆点*/
/*width:2600px;*//*共有5张照片和margin10px*/
position:absolute;/*开启绝对定位,并为父元素开启相对定位*/
/*left:-520px;*//*每向左移动520px,可见框中就会显示下一张图片*/
}
#imgList li
{
float:left;/*设置float后图片并没有成一行排列,原因是ul的大小被outer限制住了。*/
margin:0 10px;
}
#navDiv
{
position: absolute;/*设置导航栏所在的位置*/
bottom:15px;
/*left: 197px;*//*通过js来动态设置居中*/
}
#navDiv a
{
float:left;/*a为内联元素,应设置浮动*/
width: 15px;
height: 15px;
background-color: red;
margin: 0 5px;
opacity: 0.5;/*设置半透明*/
}
#navDiv a:hover
{
background-color: black;/*设置鼠标移入效果*/
}
</style>
<script type="text/javascript" src="./tool.js"></script>
<script type="text/javascript">
window.onload = function()
{
//设置imgList的宽度
var imgList = document.getElementById("imgList");
var imgArr = document.getElementsByTagName("img");
imgList.style.width = 520*imgArr.length+"px";
//设置导航按钮居中
var imgDiv = document.getElementById("navDiv");
var outer = document.getElementById("outer");
navDiv.style.left=(outer.offsetWidth - navDiv.offsetWidth)/2+"px";
var index = 0;//设置图片的索引 默认第一张
var allA = document.getElementsByTagName("a");
allA[index].style.backgroundColor = "black";
for(var i = 0; i<allA.length;i++)
{
//为每一个超链接都添加一个num属性,记录下点击第几张图片。
allA[i].num = i;
allA[i].onclick=function()
{
index = this.num;
//根据index设置偏移量,可以让可见框中显示图片。
// imgList.style.left = -520*index+"px"
setA();
//使用move函数切换图片
move(imgList,"left",-520*index,20,function(){
})
}
}
//创建一个方法用来设置选中的a
function setA(){
//遍历全部的导航块,让其变红
for(var i = 0; i<allA.length; i++)
{
allA[i].style.backgroundColor="";
//不能直接设置为红色,因为内联样式优先级太高,会使hover失效。
}
//将选中的导航块变黑
allA[index].style.backgroundColor="black";
}
}
</script>
</head>
<body>
<!-- #outer为可见框部分-->
<div id = "outer">
<ul id = "imgList">
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/2.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/3.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/4.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/5.jpg"/ style="width:500px;height:333px"></li>
</ul>
<!-- 创建导航按钮 -->
<div id="navDiv">
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
</div>
</div>
</body>
</html>
使用定时器完成轮播图的功能
使用定时器,开启定时移动图片
为了实现这个功能,我们来创建一个函数用来开启自动切换图片。(通过定时器的帮助。)
function autoChange()
{
//开启定时器,用于定时去切换图片
setInterval(function(){
index++;
//执行动画,切换图片
move(imgList,"left",-520*index,20,function(){
})
},3000);
}
我们可以看到,调用这个函数后,图片可以实现自动切换。但存在着两个问题:
(1)图片虽然切换了,但是导航块的颜色没有改变。
(2)图片不停的左移,移到index为最后一张图片时无法回到第一张图片。索引一直在自增。
我们先来解决第一个问题,我们想到了move函数最后一个参数是一个回调函数。这个回调函数可以让我们在动画执行完后,执行一些操作。我们在回调函数中执行之前定义的setA()方法。就可以轻松的解决(1)问题啦~
我们再来思考一下第二个问题,想要实现轮播的功能,当然不能仅仅从第一张图片轮播到最后一张图片,还需要能够从最后一张图片播到第一张图片。这时我们就想,能不能加一个判断,让index==最后一张图片时,回到第一张图片呢?于是我们将上面的方法改成:
function autoChange()
{
//开启定时器,用于定时去切换图片
setInterval(function(){
index++;
index=index%imgArr.length;
//执行动画,切换图片
move(imgList,"left",-520*index,20,function(){
setA();
})
},3000);
}
这时,更加鬼畜的事情发生了,虽然图片从最后一张到第一张了,但是呈现的效果是“嗖”的一下从最后一张->倒数第二张->……->第二张->第一张这样切换的。显然不符合我们的要求。
解决从最后一张到第一张图的切换
原理图如下,我们在不可见框ul的最后一张图后面,添加第一张图片。当我们切换到最后一张照片时,下一张应该移到第一张照片。当移稳后,我们瞬间将整个不可见框框移到头部。实现视觉上的最后一张到第一张图片的平稳切换。
我们现在最后一张图片后面增加第一张图片,html结构变为
<ul id = "imgList">
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/2.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/3.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/4.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/5.jpg"/ style="width:500px;height:333px"></li>
<!-- 向最后一张图的后面补上第一张图片 -->
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
</ul>
这时,还需要去设定setA()方法,使图片移动到最后一张(1)图片的时候,第一个导航块出现被选中的效果。
这时~当index为最后一张(1)图片,再立刻设置偏移量,使整个不可见框变为初始那样。
function setA()
{
if(index>=imgArr.length - 1)
{
index=0;
//实现一瞬间从最后一张照片跳回第一张照片
imgList.style.left=0;
}
//遍历全部的导航块,让其变红
for(var i = 0; i<allA.length; i++)
{
allA[i].style.backgroundColor="";
//不能直接设置为红色,因为内联样式优先级太高,会使hover失效。
}
//将选中的导航块变黑
allA[index].style.backgroundColor="black";
}
这样就图片就能实现从轮播的平缓切换啦~
吹毛求疵
其实代码如上那样修改就已经达到了我们轮播图的效果了,但是我们要更加吹毛求疵一点。由于我们实现了“轮播”和“点击切换图片”的效果。所以这两个动画是有可能“打架”的。我们应该对代码进行进一步的优化。
即,当我们“点击切换图片”的时候,“轮播”这个定时器应当关闭,避免“打架”。我们修改一下“点击切换图片”的方法
allA[i].onclick=function()
{
//当“点击切换图片时”,关闭“轮播功能”
clearInterval(timer)
index = this.num;
//根据index设置偏移量,可以让可见框中显示图片。
// imgList.style.left = -520*index+"px"
setA();
//使用move函数切换图片
move(imgList,"left",-520*index,20,function(){
//当切换图片成功后,再次开启自动切换。
autoChange();
})
}
这样功能也得到进一步优化啦~
最终代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>轮播图</title>
<style type="text/css">
*
{
margin:0;
padding:0;
}
/*设置outer可见框的样式*/
#outer
{
width:520px;
height: 333px;
margin: 50px auto;
background-color: yellowgreen;
padding:10px 0;
position:relative;/*让ul能相对于可见框来偏移*/
overflow: hidden;/*让不可见框真正的不可见*/
}
/*设置不可见框的样式 将图片排成一行*/
#imgList
{
list-style: none; /*去除li自带的小圆点*/
/*width:2600px;*//*共有5张照片和margin10px*/
position:absolute;/*开启绝对定位,并为父元素开启相对定位*/
/*left:-520px;*//*每向左移动520px,可见框中就会显示下一张图片*/
}
#imgList li
{
float:left;/*设置float后图片并没有成一行排列,原因是ul的大小被outer限制住了。*/
margin:0 10px;
}
#navDiv
{
position: absolute;/*设置导航栏所在的位置*/
bottom:15px;
/*left: 197px;*//*通过js来动态设置居中*/
}
#navDiv a
{
float:left;/*a为内联元素,应设置浮动*/
width: 15px;
height: 15px;
background-color: red;
margin: 0 5px;
opacity: 0.5;/*设置半透明*/
}
#navDiv a:hover
{
background-color: black;/*设置鼠标移入效果*/
}
</style>
<script type="text/javascript" src="./tool.js"></script>
<script type="text/javascript">
window.onload = function()
{
//设置imgList的宽度
var imgList = document.getElementById("imgList");
var imgArr = document.getElementsByTagName("img");
imgList.style.width = 520*imgArr.length+"px";
//设置导航按钮居中
var imgDiv = document.getElementById("navDiv");
var outer = document.getElementById("outer");
navDiv.style.left=(outer.offsetWidth - navDiv.offsetWidth)/2+"px";
var index = 0;//设置图片的索引 默认第一张
var allA = document.getElementsByTagName("a");
allA[index].style.backgroundColor = "black";
for(var i = 0; i<allA.length;i++)
{
//为每一个超链接都添加一个num属性,记录下点击第几张图片。
allA[i].num = i;
allA[i].onclick=function()
{
//当“点击切换图片时”,关闭“轮播功能”
clearInterval(timer)
index = this.num;
//根据index设置偏移量,可以让可见框中显示图片。
// imgList.style.left = -520*index+"px"
setA();
//使用move函数切换图片
move(imgList,"left",-520*index,20,function(){
//当切换图片成功后,再次开启自动切换。
autoChange();
})
}
}
//自动切换图片
autoChange()
//创建一个方法用来设置选中的a
function setA(){
if(index>=imgArr.length - 1)
{
index=0;
//实现一瞬间从最后一张照片跳回第一张照片
imgList.style.left=0;
}
//遍历全部的导航块,让其变红
for(var i = 0; i<allA.length; i++)
{
allA[i].style.backgroundColor="";
//不能直接设置为红色,因为内联样式优先级太高,会使hover失效。
}
//将选中的导航块变黑
allA[index].style.backgroundColor="black";
}
var timer;
//创建一个函数,用来开启自动切换图片
function autoChange()
{
//开启定时器,用于定时去切换图片
timer = setInterval(function(){
index++;
index=index%imgArr.length;
//执行动画,切换图片
move(imgList,"left",-520*index,20,function(){
setA();
})
},3000);
}
}
</script>
</head>
<body>
<!-- #outer为可见框部分-->
<div id = "outer">
<ul id = "imgList">
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/2.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/3.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/4.jpg"/ style="width:500px;height:333px"></li>
<li><img src="img/5.jpg"/ style="width:500px;height:333px"></li>
<!-- 向最后一张图的后面补上第一张图片 -->
<li><img src="img/1.jpg"/ style="width:500px;height:333px"></li>
</ul>
<!-- 创建导航按钮 -->
<div id="navDiv">
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
<a href="javascript:;"></a>
</div>
</div>
</body>
</html>
tool.js文件
function move(obj,attr,target,speed,callback)
{
//在每次开启定时器之前,关闭掉之前的定时器。
clearInterval(obj.timer);
//获取当前的left值
var current = parseInt(getStyle(obj,attr));
/*
判断速度的正负,如果是从0->800移动,speed为正;
如果是从800->0移动,speed为负。
*/
if(current > target)
{
speed = -speed;
}
//开启一个定时器,用来执行动画效果
//向执行动画的对象中添加一个timer属性,用来保存它自己的定时器的标识。
obj.timer = setInterval(function()
{
//获取box1的原来的left值
var oldvalue = parseInt(getStyle(obj,attr));
//在oldvalue的基础上增加。
var newvalue = oldvalue + speed;
//向左移动时,需要判断newvalue是否小于target
//向右移动时,需要判断newvalue是否大于target
if((speed<0 && newvalue < target) || (speed>0 && newvalue > target))
{
newvalue = target;
}
//attr为变量,需要用[]的形式而不能是.的形式
obj.style[attr] = newvalue + "px";
//当元素移动到800px时停止执行动画
if(newvalue == target)
{
clearInterval(obj.timer);
//动画执行完毕,调用回调函数;
callback && callback();
}
},30);
}