說一下思路:和我上一篇博客中用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
這篇博客是我目前寫的最長的一篇,時間跨度兩天,中間多有疏漏或者不正確的地方還希望能指出,我改正。