使用原生JS且稳定无bug的轮播图
20190313,花了整个白天跟着慕课网的教程做了这个轮播图,受益颇多。老师讲的切图过程中不响应点击事件那里有点bug,已经修正。
5张图片放在img文件夹中,分别取名timg1.jpg, timg2.jpg……timg5.jpg。图片分辨率均为600*400
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Slider</title> 6 <style> 7 * { 8 padding: 0; 9 margin: 0; 10 -webkit-box-sizing: border-box; 11 -moz-box-sizing: border-box; 12 box-sizing: border-box; 13 } 14 #container { 15 position: relative; 16 height: 400px; 17 width: 600px; 18 margin: 100px auto; 19 overflow: hidden; 20 } 21 /* 怎么让7张图片排成一排呢?将7张图片的父容器宽度设为600*7,img再float */ 22 /* 值得注意的一点是,这个图片框必须position为absolute,这样才能让JS通过修改该元素的left值来定位 */ 23 #pics { 24 position: absolute; 25 width: 4200px; 26 height: 100%; 27 z-index: 1; 28 } 29 /* 为什么img不float时,就排不下?img之间的间距是哪来的呢?不是reset了吗? */ 30 #pics>img { 31 float: left; 32 } 33 #dots { 34 position: absolute; 35 height: 10px; 36 width: 300px; 37 left: 150px; 38 bottom: 10px; 39 z-index: 2; 40 } 41 /* 这里比较陌生,需要注意 */ 42 #dots>span { 43 cursor: pointer; 44 float: left; 45 height: 6px; 46 width: 50px; 47 margin: 2px 5px; 48 background: rgb(253, 253, 253); 49 border-radius: 2px; 50 box-shadow: 0px 1px 2px rgb(223, 223, 223); 51 } 52 #dots .on { 53 background: orange; 54 } 55 /* 这里将a标签当块级元素处理 */ 56 .arrow { 57 position: absolute; 58 cursor: pointer; 59 text-decoration: none; 60 display: none; 61 height: 40px; 62 width: 30px; 63 line-height: 40px; 64 font-size: 20px; 65 font-weight: 500; 66 color: rgb(235, 235, 235); 67 /* text-align: center; */ 68 background: rgba(90, 90, 90, 0.4); 69 z-index: 2; 70 } 71 #prev { 72 left: 0; 73 top: 165px; 74 padding-left: 5px; 75 border-top-right-radius: 20px; 76 border-bottom-right-radius: 20px; 77 } 78 #next { 79 right: 0; 80 top: 165px; 81 padding-left: 10px; 82 border-top-left-radius: 20px; 83 border-bottom-left-radius: 20px; 84 } 85 #container:hover .arrow{display: block;} 86 .arrow:hover {background: rgba(82, 82, 82, 0.5)} 87 </style> 88 89 </head> 90 <body> 91 <div id="container"> 92 <!-- 这里为什么默认pics容器的绝对定位的left为-600呢?因为第一张图是timg5 --> 93 <div id="pics" style="left: -600px;"> 94 <img src="img/timg5.jpg" alt="1"> 95 <img src="img/timg1.jpg" alt="1"> 96 <img src="img/timg2.jpg" alt="2"> 97 <img src="img/timg3.jpg" alt="3"> 98 <img src="img/timg4.jpg" alt="4"> 99 <img src="img/timg5.jpg" alt="5"> 100 <img src="img/timg1.jpg" alt="5"> 101 </div> 102 103 <div id="dots"> 104 <!-- 注意这里的index="x"是一个自定义属性 --> 105 <span index="1" class="on"></span> 106 <span index="2"></span> 107 <span index="3"></span> 108 <span index="4"></span> 109 <span index="5"></span> 110 </div> 111 112 <a href="javascript:;" id="prev" class="arrow"><</a> 113 <a href="javascript:;" id="next" class="arrow">></a> 114 </div> 115 116 <script> 117 window.onload = function() { 118 var container = document.getElementById('container'); 119 var pics = document.getElementById('pics'); 120 var buttons = document.getElementById('dots').getElementsByTagName('span'); 121 var prev = document.getElementById('prev'); 122 var next = document.getElementById('next'); 123 var index = 1; //这个全局变量index表示当前亮起的那个指示条的下标+1 124 var isMoving = false;//是否在切换运动中 125 var timer; //最后实现自动播放时用的 126 127 //获取完元素就开始基础的事件绑定,先实现点击左右箭头切换 128 //最开始分别写左右按钮 129 //值得注意的是onclick和addEventListener的用法,比如xx.onclick=animate(-/+600)是无效的!必须套在匿名函数中。但是若animate函数不用传参,则可以不套。 130 //下面五个条的亮暗和左右点击操作有关,于是showButton函数要在左右按钮的onclick事件里面执行 131 prev.onclick = function() { 132 if(!isMoving){ 133 if(index == 1) { 134 index = 5; 135 } else { 136 index--; 137 } 138 showButton(); 139 animate(600); 140 } 141 } 142 next.onclick = function() { 143 if(!isMoving) { 144 if(index == 5) { 145 index = 1; 146 } else { 147 index++; 148 } 149 150 showButton(); 151 animate(-600); 152 } 153 } 154 155 function animate(offset) { 156 // var isMoving = true; 这样写就没用啦!因为这样没改变外面的isMoving值,那些click事件一直获取到外部的isMoving==false,所以运动时还是会响应 157 isMoving = true; 158 var newLeft = parseInt(pics.style.left) + offset; 159 //下面三个变量的定义和go函数的if语句是来实现平移动画的。 160 var time = 300; //位移总的时间 161 var interval = 10; //位移间隔时间 162 var speed = offset/(time/interval); //每次的位移量 163 164 //当快速地点击切换图片时,会进行大量的计算,还在运动过程中就又要响应,这是既不合理又折磨浏览器的。
//所以应该设定运动过程中不响应切换图片的操作。设一个参数表示是否在运动的状态,参数放在哪呢?当然不是放在这里啦。
//运动状态是一个宏观的大家都能得到的,并且那些外部的点击事件也要参考这个状态来决定是否执行。这里是用来“制造运动”的。
//所以一执行这个animate函数 就开始运动了,执行到else里面就运动结束。 接下来就是通过这个isMoving状态来控制那些点击事件了。 165 166 //记住左移时 offset为正,speed为正。越左边pics.style.left越大。 167 function go() { 168 if ( (speed < 0 && parseInt(pics.style.left) > newLeft) || (speed > 0 && parseInt(pics.style.left) < newLeft) ) { 169 pics.style.left = parseInt(pics.style.left) + speed + 'px'; 170 setTimeout(go, interval);//递归 171 } 172 else { 173 isMoving = false; 174 //下面这些是第一步骤。 175 pics.style.left = newLeft + 'px'; 176 //到这里要实现无限滚动,发现需要多次用到pics.style.left值,便存到newLeft 177 if(newLeft > -600) { 178 pics.style.left = -3000 + 'px'; 179 } 180 if(newLeft < -3000) { 181 pics.style.left = -600 + 'px'; 182 } 183 } 184 } 185 go(); //不调用就不会执行哦 186 } 187 188 //注意亮起对应的小长条之前要把那个亮着的长条给灭掉 189 //还有很重要的一点,如果点右箭头使得index到5了,而buttons[5]不存在,控制台报错,左箭头使index减到-1也是如此。
//因此要在左右箭头的点击函数里改进。为什么到那里而不在showbutton函数里呢?因为showButton并没有控制index的加减。 190 function showButton() { 191 for(var i = 0; i < buttons.length; i++) { 192 if(buttons[i].className == 'on') { 193 buttons[i].className = ''; 194 break; 195 } 196 } 197 buttons[index-1].className = 'on'; 198 } 199 200 //接下来实现点击下面5个长条(button)来跳转到对应的图片,像左右箭头一样调用animate函数,不同的是左右箭头知道offset为±600,
//这里则要算出跳了多少个点再乘-600px。这里很巧妙,利用span里面自定义的属性index和现在程序里表示当前哪个class为on的button的index值来做比较。
//前者是目标元素,后者是亮的元素。 201 for(var i = 0; i < buttons.length; i++) { 202 buttons[i].onclick = function() { 203 //下面这一句是用来判断当前的button是不是已经亮了,如果是的话就什么都不干,没必要进行接下去的那些计算。这是一个小优化点。 204 if(!isMoving) { 205 if(this.className == 'on') { return; } 206 var myIndex = parseInt(this.getAttribute('index')); 207 var offset = -600 * (myIndex - index); 208 209 animate(offset); 210 211 //注意下面别忘了 212 index = myIndex; 213 showButton(); 214 } 215 216 } 217 } 218 219 //接下来就是加上切换时的移动动画。在哪加呢?在掌控left值的animate函数里面。 220 221 //最后是自动轮播的功能 222 function play() { 223 timer = setInterval(function() { 224 next.onclick(); 225 }, 2000); 226 } 227 228 function stop() { 229 clearInterval(timer); 230 } 231 232 container.onmouseover = stop; 233 container.onmouseout = play; 234 235 play(); 236 } 237 </script> 238 </body> 239 </html>