用原生的javascript 實現一個無限滾動的輪播圖

說一下思路:和我上一篇博客中用JQ去寫的輪播圖有相同點和不一樣點html

相同點:

  • 首先頁面佈局是同樣的
  • 一樣是改變.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>

須要注意的地方:ide

  1. 執行完畢inner.style.left = parseInt(inner.style.left) + offset + "px"; 後 inner.style.left的值爲新位置的值,後面的判斷須要用新的值去判斷
  2. index的值爲1-5,作成a元素的下標時須要 index-1
  3. 注意調用的showButton函數的位置,須要在獲得index的值的後調用
  4. 須要給.inner盒子添加行內樣式 style="left:-600px;",不添加出現inner.style.left獲取不到值的狀況
  5. 獲取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>

須要注意:函數

  1. 第72行 index = id 把index的值更新爲當前的索引index。
  2. 由於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函數我以爲是這個輪播圖中最難的點,我常常有地方轉不過彎來。佈局

須要注意的地方:學習

  1. 每次位移一小段距離,終點怎麼去判斷,也就是何時會中止,.inner盒子只能往左邊或者右邊移動,點擊next按鈕 .inner往左邊移動,是添加一個負值距離,點擊prev按鈕 .inner往右移動,是添加一個正的left距離 第52行判斷條件的意思是,若是speed小於0,獲取當前.inner盒子的left的值與目標newLeft值比較 若是大於他則不停的去加上-speed去變小 與newLeft相同爲止 或者speed大於0,獲取當前.inner盒子的left的值與目標newLeft值比較 若是小於他則不停的去加上speed去變大 與 newLeft相同爲止。
  2. newLeft = parseInt(inner.style.left) + offset; 表示最終目標值,存進了變量newLeft中,下面inner.style.left獲取的都是如今的left值
  3. go函數裏面用的是setTimeout()來遞歸,經過判斷條件,來遞歸go函數。開始我用的是setInterval()方法,致使出現了奇異的動畫效果,思路錯了,應該在if前面添加一個clearInterval()清除方法,由於若是不清除的話會不斷的調用go函數,致使go函數永遠都不會結束,就致使了畫面狂閃現象。 setTimeout()方法是在什麼時間之後幹什麼,幹完拉倒。setInterval()不停的去調用函數,直到clearInterval()被調用或者窗口被關閉。
  4. 注意第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>

須要注意的地方:優化

  1. 觸發next的點擊事件,能夠寫成next.onclick()來觸發
  2. 給.pic添加事件 不能寫成pic.onmouseover = stop(),加了括號後表明當即調用函數,而不是咱們須要的懸浮在pic盒子上時調用.

總結:第一次學習這個輪播圖時,由於思路跟不上,致使看不懂,而後我又從簡單的作起,好比我先學習作了一個自動輪播標籤頁(前面博客有總結),而後又學習用jq寫了一個簡單的輪播圖,再過來學習這個難度大的,按部就班去學習,就會發現本身能懂甚至寫出來這個輪播圖了,附上我學習的視頻連接地址。動畫

標籤切換地址:http://www.imooc.com/learn/176this

JQ輪播圖地址:http://www.cnblogs.com/yewenxiang/p/6100206.htmlspa

原生js輪播圖地址:http://www.imooc.com/learn/176

這篇博客是我目前寫的最長的一篇,時間跨度兩天,中間多有疏漏或者不正確的地方還但願能指出,我改正。

相關文章
相關標籤/搜索