用原生的javascript 实现一个无限滚动的轮播图
说一下思路:和我上一篇博客中用JQ去写的轮播图有相同点和不同点
相同点:
- 首先页面布局是一样的
- 同样是改变.inner盒子的位置去显示不同的图片
不同点:
- 为了实现无限滚动需要多添加两张重复的图片
- 左右切换和前面的方法有所不同,前面是获取当前的索引值乘以-600px当做位移距离,现在是需要获取当前.inner的位置来加上或者减去-600来实现
下面来一步步的去实现轮播图:
首先是html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> ul{ list-style: none; position: absolute; bottom: 0; left: 175px; } ul li{ float: left; } ul li a{ display: block; width: 20px; height: 20px; border-radius: 50%; background-color: #ffbeaa; margin-left: 5px; opacity: 0.6; } ul li a.active{ background-color: red; } .inner{ width: 4200px; height: 400px; position: absolute; } .inner img{ display: block; float: left; } .pic{ height: 400px; width: 600px; overflow: hidden; position: relative; } .prev,.next{ position: absolute; top: 190px; opacity: 0.6; } .next{ right: 0; } </style> <script> </script> </head> <body> <div class="pic" id="pic"> <div class="inner" id="inner" style="left:-600px;"> <img src="img/5.jpg" alt=""> <img src="img/1.jpg" alt=""> <img src="img/2.jpg" alt=""> <img src="img/3.jpg" alt=""> <img src="img/4.jpg" alt=""> <img src="img/5.jpg" alt=""> <img src="img/1.jpg" alt=""> </div> <ul id="ul"> <li><a href="#" class="active" id="1"></a></li> <li><a href="#" id="2"></a></li> <li><a href="#" id="3"></a></li> <li><a href="#" id="4"></a></li> <li><a href="#" id="5"></a></li> </ul> <a href="#" class="prev" id="prev"><img src="img/slider-prev.png" alt=""></a> <a href="#" class="next" id="next"><img src="img/slider-next.png" alt=""></a> </div> </body> </html>
第一步添加左右点击切换:
<script> //文档加载完毕后执行函数 window.onload=function(){ var pic = document.getElementById("pic"); var inner = document.getElementById("inner"); var li = document.getElementById("ul").getElementsByTagName("a"); var prev = document.getElementById("prev"); var next = document.getElementById("next"); //设置索引初始值,点击自增或者自减,根据index值来给按钮添加颜色 var index = 1; //左点击事件 prev.onclick = function(){ //调用动画函数,传入正的600,为每次的偏移量 animate(600); //设置索引的范围,不能小于1 if(index==1){ index=5; }else{ index--; } //调用添加颜色函数 showButton(); } //右点击事件 next.onclick = function(){ //调用动画函数,传入负的600,为每次的偏移量 animate(-600); //设置索引的范围,不能超过5 if(index==5){ index=1; }else{ index++; } showButton(); } //动画函数,offset参数为偏移量 function animate(offset){ //获取现在.inner盒子的位置加上偏移量 赋值 给.inner盒子 inner.style.left = parseInt(inner.style.left) + offset + "px"; //判断新的位置,如果小于-3000则变为-600px,如果大于-600则变为-3000px if(parseInt(inner.style.left) < -3000){ inner.style.left = -600 + "px"; } if(parseInt(inner.style.left) > -600){ inner.style.left = -3000 + "px"; } } //按钮添加颜色函数 function showButton(){ //遍历每个a元素,如果有active类 则替换为空字符串,也就是移除这个类 for(var i=0;i<li.length;i++){ if(li[i].className=="active"){ li[i].className=""; //移除后就没必要去循环了,做一个优化。 break; } } //根据当前的index值,找到对应的a元素添加active类 li[index-1].className="active"; } } </script>
需要注意的地方:
- 执行完毕inner.style.left = parseInt(inner.style.left) + offset + “px”; 后 inner.style.left的值为新位置的值,后面的判断需要用新的值去判断
- index的值为1-5,做成a元素的下标时需要 index-1
- 注意调用的showButton函数的位置,需要在得到index的值的后调用
- 需要给.inner盒子添加行内样式 style=”left:-600px;”,不添加出现inner.style.left获取不到值的情况
- 获取a元素不能 var li = document.getElementById(“ul”).getElementsByTagName(“li”).getElementsByTagName(“a”);去获取,因为getElementsByTagName(“li”)获取的是一个包含5个li的数组,需要加索引值,比如var li = document.getElementById(“ul”).getElementsByTagName(“li”)[0].getElementsByTagName(“a”);
第二步:添加五个按钮切换
1 <script> 2 //文档加载完毕后执行函数 3 window.onload=function(){ 4 var pic = document.getElementById("pic"); 5 var inner = document.getElementById("inner"); 6 var li = document.getElementById("ul").getElementsByTagName("a"); 7 var prev = document.getElementById("prev"); 8 var next = document.getElementById("next"); 9 //设置索引初始值,点击自增或者自减,根据index值来给按钮添加颜色 10 var index = 1; 11 //左点击事件 12 prev.onclick = function(){ 13 //调用动画函数,传入正的600,为每次的偏移量 14 animate(600); 15 //设置索引的范围,不能小于1 16 if(index==1){ 17 index=5; 18 }else{ 19 index--; 20 } 21 //调用添加颜色函数 22 showButton(); 23 } 24 //右点击事件 25 next.onclick = function(){ 26 //调用动画函数,传入负的600,为每次的偏移量 27 animate(-600); 28 //设置索引的范围,不能超过5 29 if(index==5){ 30 index=1; 31 }else{ 32 index++; 33 } 34 showButton(); 35 } 36 //动画函数,offset参数为偏移量 37 function animate(offset){ 38 //获取现在.inner盒子的位置加上偏移量 赋值 给.inner盒子 39 inner.style.left = parseInt(inner.style.left) + offset + "px"; 40 //判断新的位置,如果小于-3000则变为-600px,如果大于-600则变为-3000px 41 if(parseInt(inner.style.left) < -3000){ 42 inner.style.left = -600 + "px"; 43 } 44 if(parseInt(inner.style.left) > -600){ 45 inner.style.left = -3000 + "px"; 46 } 47 } 48 //按钮添加颜色函数 49 function showButton(){ 50 //遍历每个a元素,如果有active类 则替换为空字符串,也就是移除这个类 51 for(var i=0;i<li.length;i++){ 52 if(li[i].className=="active"){ 53 li[i].className=""; 54 //移除后就没必要去循环了,做一个优化。 55 break; 56 } 57 } 58 //根据当前的index值,找到对应的a元素添加active类 59 li[index-1].className="active"; 60 } 61 //遍历五个按钮 62 for(var i=0;i<li.length;i++){ 63 //给五个按钮添加点击事件 64 li[i].onclick=function(){ 65 //获取当前的id值 66 var id = parseInt(this.getAttribute("id")); 67 //减去原来的index值,乘以-600 得到偏移量,调用偏移函数 68 var offset = (id-index) * -600; 69 //调用偏移函数 70 animate(offset); 71 //把index的值更新 72 index = id; 73 //调用改变背景色函数 74 showButton(); 75 } 76 } 77 } 78 </script>
需要注意:
- 第72行 index = id 把index的值更新为当前的索引index。
- 因为id属性不是HTML自带的属性。不能li.style.id 这样去获取,而是使用getAttribute(“id”)方法,这个方法HTML自带属性和自定义属性都能获取
第三步:添加animate函数添加动画函数
1 <script> 2 window.onload=function(){ 3 var pic = document.getElementById("pic"); 4 var inner = document.getElementById("inner"); 5 var li = document.getElementById("ul").getElementsByTagName("a"); 6 var prev = document.getElementById("prev"); 7 var next = document.getElementById("next"); 8 var index = 1; 9 //通过state的状态 来判断是否执行animate函数 10 var state = false; 11 prev.onclick = function(){ 12 //如果state=false 代表动画函数没有执行完毕,则此次点击无效 13 if(state){ 14 return; 15 } 16 animate(600); 17 if(index==1){ 18 index=5; 19 }else{ 20 index--; 21 } 22 showButton(); 23 } 24 next.onclick = function(){ 25 //如果state=false 代表动画函数没有执行完毕,则此次点击无效 26 if(state){ 27 return; 28 } 29 animate(-600); 30 if(index==5){ 31 index=1; 32 }else{ 33 index++; 34 } 35 showButton(); 36 } 37 38 function animate(offset){ 39 //调用animate函数后 state的值变为true 40 state = true; 41 //动画执行总的时间 42 var time = 300; 43 //每次位移的间隔时间 44 var interval = 10; 45 //每次位移量 46 var speed = offset/(time/interval); 47 48 var newLeft = parseInt(inner.style.left) + offset; 49 //动画函数 50 function go(){ 52 if((speed < 0 && parseInt(inner.style.left) > newLeft) || (speed > 0 && parseInt(inner.style.left) < newLeft)){ 53 inner.style.left = parseInt(inner.style.left) + speed + "px"; 54 //通过延时定时器不断的去调用自身go函数。直到达到目标位置 55 setTimeout(go,interval); 56 }else{ 57 //达到目标位置后 state 状态变为 false 58 state = false; 59 //跟新.inner盒子的值为目标的位置 60 inner.style.left = newLeft + "px"; 61 //盒子到达目标位置后做一个判断,如果跑到假的第一张图和第五张图上时,马上瞬间跑到真正的第一张图或者第五张图 62 if(parseInt(inner.style.left) < -3000){ 63 inner.style.left = -600 + "px"; 64 } 65 if(parseInt(inner.style.left) > -600){ 66 inner.style.left = -3000 + "px"; 67 } 68 } 69 } 70 go(); 71 72 } 73 function showButton(){ 74 for(var i=0;i<li.length;i++){ 75 if(li[i].className=="active"){ 76 li[i].className=""; 77 break; 78 } 79 } 80 li[index-1].className="active"; 81 } 82 for(var i=0;i<li.length;i++){ 83 li[i].onclick=function(){ 84 var id = parseInt(this.getAttribute("id")); 85 var offset = (id-index) * -600; 86 //如果state=false 代表动画函数没有执行完毕,则此次点击无效 87 if(state){ 88 return; 89 } 90 animate(offset); 91 index = id; 92 showButton(); 93 } 94 } 95 }
做这个go函数我觉得是这个轮播图中最难的点,我经常有地方转不过弯来。
需要注意的地方:
- 每次位移一小段距离,终点怎么去判断,也就是什么时候会停止,.inner盒子只能往左边或者右边移动,点击next按钮 .inner往左边移动,是添加一个负值距离,点击prev按钮 .inner往右移动,是添加一个正的left距离 第52行判断条件的意思是,如果speed小于0,获取当前.inner盒子的left的值与目标newLeft值比较 如果大于他则不停的去加上-speed去变小 与newLeft相同为止 或者speed大于0,获取当前.inner盒子的left的值与目标newLeft值比较 如果小于他则不停的去加上speed去变大 与 newLeft相同为止。
- newLeft = parseInt(inner.style.left) + offset; 表示最终目标值,存进了变量newLeft中,下面inner.style.left获取的都是现在的left值
- go函数里面用的是setTimeout()来递归,通过判断条件,来递归go函数。开始我用的是setInterval()方法,导致出现了奇异的动画效果,思路错了,应该在if前面添加一个clearInterval()清除方法,因为如果不清除的话会不断的调用go函数,导致go函数永远都不会结束,就导致了画面狂闪现象。 setTimeout()方法是在什么时间以后干什么,干完拉倒。setInterval()不停的去调用函数,直到clearInterval()被调用或者窗口被关闭。
- 注意第70行,写完go函数后需要调用他才会执行。
第四步:最终版,添加自动轮播效果
1 <script> 2 window.onload=function(){ 3 var pic = document.getElementById("pic"); 4 var inner = document.getElementById("inner"); 5 var li = document.getElementById("ul").getElementsByTagName("a"); 6 var prev = document.getElementById("prev"); 7 var next = document.getElementById("next"); 8 var index = 1; 9 var timer = null; 10 //设置一个变量来存放自动轮播定时器 11 var timer2 = null; 12 var state = false; 13 prev.onclick = function(){ 14 if(state){ 15 return; 16 } 17 animate(600); 18 if(index==1){ 19 index=5; 20 }else{ 21 index--; 22 } 23 showButton(); 24 } 25 next.onclick = function(){ 26 if(state){ 27 return; 28 } 29 animate(-600); 30 if(index==5){ 31 index=1; 32 }else{ 33 index++; 34 } 35 showButton(); 36 } 37 38 function animate(offset){ 39 state = true; 40 var time = 300; 41 var interval = 10; 42 var speed = offset/(time/interval); 43 44 var newLeft = parseInt(inner.style.left) + offset; 45 function go(){ 46 clearInterval(timer); 47 if((speed < 0 && parseInt(inner.style.left) > newLeft) || (speed > 0 && parseInt(inner.style.left) < newLeft)){ 48 inner.style.left = parseInt(inner.style.left) + speed + "px"; 49 timer=setInterval(go,interval); 50 }else{ 51 state = false; 52 inner.style.left = newLeft + "px"; 53 if(parseInt(inner.style.left) < -3000){ 54 inner.style.left = -600 + "px"; 55 } 56 if(parseInt(inner.style.left) > -600){ 57 inner.style.left = -3000 + "px"; 58 } 59 } 60 } 61 go(); 62 63 } 64 function showButton(){ 65 for(var i=0;i<li.length;i++){ 66 if(li[i].className=="active"){ 67 li[i].className=""; 68 break; 69 } 70 } 71 li[index-1].className="active"; 72 } 73 for(var i=0;i<li.length;i++){ 74 li[i].onclick=function(){ 75 var id = parseInt(this.getAttribute("id")); 76 var offset = (id-index) * -600; 77 if(state){ 78 return; 79 } 80 animate(offset); 81 index = id; 82 showButton(); 83 } 84 } 85 //通过定时器来不断的点击 next按钮 来实现轮播效果. 86 function play(){ 87 timer2 = setInterval(function(){ 88 next.onclick(); 89 },3000); 90 } 91 //停止轮播函数,清除定时器 92 function stop(){ 93 clearInterval(timer2); 94 } 95 //给.pic添加移进悬浮和移出事件 96 pic.onmouseover = stop; 97 pic.onmouseout = play; 98 //第一次访问页面开始轮播 99 play(); 100 } 101 </script>
需要注意的地方:
- 触发next的点击事件,可以写成next.onclick()来触发
- 给.pic添加事件 不能写成pic.onmouseover = stop(),加了括号后代表立即调用函数,而不是我们需要的悬浮在pic盒子上时调用.
总结:第一次学习这个轮播图时,因为思路跟不上,导致看不懂,然后我又从简单的做起,比如我先学习做了一个自动轮播标签页(前面博客有总结),然后又学习用jq写了一个简单的轮播图,再过来学习这个难度大的,循序渐进去学习,就会发现自己能懂甚至写出来这个轮播图了,附上我学习的视频链接地址。
标签切换地址:http://www.imooc.com/learn/176
JQ轮播图地址:http://www.cnblogs.com/yewenxiang/p/6100206.html
原生js轮播图地址:http://www.imooc.com/learn/176
这篇博客是我目前写的最长的一篇,时间跨度两天,中间多有疏漏或者不正确的地方还希望能指出,我改正。