布局:
slider > ul > li
slider > arrow > a> img
arrow : z-index:2 ;
注意,ul 里面放着所有輪播圖的圖片,所以 ul 的寬度必須足夠大能夠容納所有圖片,這里有4張圖片,ul寬度設置為 600%
功能需求:
1,鼠標經過輪播圖模塊,左右按鈕顯示,離開隱藏左右按鈕
slider.addEventListener(“mouseover",function(){ arrowLeft.style.display="block"; arrowRight.style.display="block"; }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display="none"; arrowRight.style.display="none"; })
2,動態生成小圓圈
①:核心思路:小圓圈的個數要跟圖片張數一致
②:所以首先先得到 ul 里面圖片的張數(圖片放入 li 中,所以就是 li 的個數)
③:利用循環動態生成小圓圈(這個小圓圈要放入 ol 里面)
④:創建節點 createElement("li")
⑤:插入節點:ol.appendChild (li)
⑥:第一個小圓圈需要添加 current 類
var ul=document.querySelector("ul"); var ol=document.querySelector(".circle"); var imgs=ul.children; for(var i=0; i<imgs.length; i++) { document.createElement("li"); ol.appendChild(li); }
ol.children[0].className="current";
3, 小圓圈的排他思想
①點擊哪個小圓圈,哪個小圓圈就添加 " current " 類
②其余的小圓圈就移除這個 current 類
③注意:我們在剛才生成小圓圈的同時,就可以直接綁定這個點擊事件了。
for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); ol.appendChild(li); li..addEventListener("click" , function(){ for(var j=0; j<ol.children.length; j++) { ol.children[j].className=" "; } this.className="current" ; }) } ol.children[0].className="current";
4,點擊小圓圈滾動圖片
①此時用到 animate動畫函數,將 js 文件引入 (注意,因為 index.js 依賴 animate.js,所以, animate.js 要寫到 index.js 上面)
②使用動畫函數的前提,該元素必須有定位(ul)
③注意是 ul 移動,不是 小 li
④滾動圖片的核心算法:點擊某個小圓圈,就讓圖片滾動,小圓圈的索引號乘以圖片的寬度 作為 ul 的移動距離
⑤此時需要知道小圓圈的索引號,我們可以下生成小圓圈的時候,給它設置一個自定義屬性,點 擊的時候獲取這個自定義屬性即可。
for(var i=0 ; i<imgs.length ; i++) { document.createElement("li"); ol.appendChild(li); li.setAttribute("index" , i); li.addEventListener("click", function(){ for(var j=0; j<ol.children.length; j++) { ol.children[j].className=""; } this.className="current"; var index=this.getAttribute("index"); var sliderWidth=slider.offsetWidth; animate(ul , -index*sliderWidth); }) } ol.children[0].className="current";
5,右側按鈕無縫滾動
①點擊右側按鈕一次,就讓圖片滾動一張
②聲明一個變量num , 點擊一次,自增 1,讓這個變量乘以圖片寬度,就是 ul 的滾動距離
③圖片無縫滾動原理:
把 ul 第一個 li 復制一份,放到 ul 的最后面,
當圖片滾動到克隆的最后一張圖片時,讓ul快速的,不做動畫的跳到最左側:left 為0,
同時num賦值為0,可以從新開始滾動圖片了。
④ 克隆第一張圖片
克隆 ul 第一個 li , cloneNode( ) , 加 true 深克隆, 復制里面的子節點,false 淺克隆
添加到 ul 最后面 appendChild()
var imgLast=ul.children[0].cloneNode(true);
ul.appendChild(imgLast);
var num=0; arrowRight.addEventListener("click" , function(){ if(num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul, -num*sliderWidth); })
//這里必須是先判斷,再加加,再執行
6,小圓圈跟隨右側按鈕一起變化
①最簡單的 做法是再聲明一個變量 circle , 每次點擊自增 1,注意,左側按鈕也需要這個變量, 因此要聲明全局變量
②但是圖片有5張,小圓圈只有4個少一個,必須加一個判斷條件,
③如果 circle==4 ,就重新復原為 0
var num=0; var circle=0; arrowRight.addEventListener("click", function(){ if(num==ul.children.length) { ul.style.left=0; num=0; } num++; animate(ul, -num*sliderWidth); circle++; //這里必須是先加加,再判斷,再執行 if(circle==ol.children.length) { circle=0; } for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; })
7,到這一步,還有兩個bug 需要解決
①當點擊小圓圈讓圖片播放到第三張,下面的小圓圈停留在第三個(索引號等於2)的時候,點擊右側按鈕,發現下一張圖片並不是第4張圖片,而是第二張圖片
②原因就是點擊右側按鈕的時候,num值與點擊小圓圈時候的 circle 沒有關系
③解決方法:點擊小圓圈的時候,獲取小圓圈當前的索引號,然后把小圓圈當前的索引號 circle 賦給 num ,這樣再點擊右側按鈕的時候,就可以在 circle 的基礎上自增了。
④第二個bug :上面的bug解決之后,點擊小圓圈讓圖片播放到第三張,再點擊右側按鈕,圖片可以順利播放到第四張,但是下面的小圓圈卻顯示在第二個
⑤原因還是因為點擊右側按鈕的時候,右側按鈕點擊次數的索引號 num 與 之后點擊小圓圈的 circle 沒有建立聯系
⑥解決方案就是,在點擊右側按鈕的時候,獲取右側按鈕點擊次數當前的索引號,然后把當前的索引號賦給 circle,這樣再點擊小圓圈的時候,就可以在 num 的基礎上 自增了。
li.addEventListener("click ,function(){ for(var j=0; j<ol.children.length;j++) { ol.children[j].className=""; } this.className="current"; var index=this.getAttribute("index"); num=index; circle=index; animate(ul, -index*sliderWIdth); })
8,左側按鈕功能制作,方法:直接將右側按鈕點擊事件復制過來,修改里面的參數即可,注意一些參數的修改
arrowLeft.addEventListener(click, function(){ if(num==0) { ul.style.left= -(ul.children.length-1)*sliderWidth +"px"; num=ul.children.length-1; } num--; animate(ul , -num*sliderWidth); circle--; if(circle<0) { circle=ol.children.length-1; } for(var i=0;i<ol.children.length ; i++) { ol.childdren[i].className=" " ; } ol.children[circle].className="current"; })
9,代碼優化
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠標經過,左右按鈕顯示,鼠標離開,左右按鈕隱藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; }) //2,動態生成小圓圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //記錄當前小圓圈的索引號,通過自定義屬性來做 ol.appendChild(li); //3,小圓圈的排他思想,我們可以直接在生成小圓圈的同時直接綁定點擊事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,點擊小圓圈,移動圖片,當然移動的是 ul ,ul 的移動距離=小圓圈的索引號乘以圖片的寬度,注意是負值 var index=this.getAttribute("index");//當我們點擊了某個小 li ,就拿到當前小 li 的索引號 //var sliderWidth=slider.offsetWidth; 下面右側按鈕點擊事件也用到這個值,所以把它放到最上面 num=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給 num circle=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,點擊右側按鈕,圖片滾動一張 var imgLast=ul.children[0].cloneNode(true); //克隆第一張圖片 ul.appendChild(imgLast); var num=0; var circle=0; arrowRight.addEventListener("click",function () { if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth); //6,點擊右側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle++; if (circle==ol.children.length) { circle=0; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current";
這里可以封裝成一個circleChange函數
circleChange(); })
//7,點擊左側按鈕,圖片滾動一張 arrowLeft.addEventListener("click",function () { if (num==0) { // ul.style.left = -(ul.children.length - 1)*sliderWidth + "px"; // num = ul.children.length - 1; 這里可以優化一下
num=ul.children.length -1
ul.style.left= -num*sliderWidth +"px";
}
num--;
animate(ul,-num*sliderWidth); //8,點擊左側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放
circle--;
if (circle<0) {
circle=ol.children.length-1;
}
// for(var i=0;i<ol.children.length;i++)
// {
// ol.children[i].className="";
// }
// ol.children[circle].className="current";
circleChange() })
function circleChange() {
for(var i=0;i<ol.children.length;i++) {
ol.children[i].className="";
}
ol.children[circle].className="current";
}
})
10,自動播放功能
①添加一個定時器
②自動播放輪播圖,實際就類似於點擊了右側按鈕
③此時我們使用手動調用右側按鈕點擊事件 arrowRight.click();
④鼠標經過slider就停止定時器
⑤鼠標離開slider就開啟定時器
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠標經過,左右按鈕顯示,鼠標離開,左右按鈕隱藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; clearInterval(timer); }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; timer=setInterval(function () { arrowRight.click(); },1000); }) //2,動態生成小圓圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //記錄當前小圓圈的索引號,通過自定義屬性來做 ol.appendChild(li); //3,小圓圈的排他思想,我們可以直接在生成小圓圈的同時直接綁定點擊事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,點擊小圓圈,移動圖片,當然移動的是 ul ,ul 的移動距離=小圓圈的索引號乘以圖片的寬度,注意是負值 var index=this.getAttribute("index");//當我們點擊了某個小 li ,就拿到當前小 li 的索引號 //var sliderWidth=slider.offsetWidth; 下面右側按鈕點擊事件也用到這個值,所以把它放到最上面 num=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給 num circle=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,點擊右側按鈕,圖片滾動一張 var imgLast=ul.children[0].cloneNode(true); //克隆第一張圖片 ul.appendChild(imgLast); var num=0; var circle=0; arrowRight.addEventListener("click",function () { if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth); //6,點擊右側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle++; if (circle==ol.children.length) { circle=0; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange(); }) //7,點擊左側按鈕,圖片滾動一張 arrowLeft.addEventListener("click",function () { if (num==0) { // ul.style.left = -(ul.children.length - 1)*sliderWidth + "px"; // num = ul.children.length - 1; num=ul.children.length-1; ul.style.left= -num*sliderWidth +"px"; } num--; animate(ul,-num*sliderWidth); //8,點擊左側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle--; if (circle<0) { circle=ol.children.length-1; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange() }) function circleChange() { for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; } //9,自動播放輪播圖 var timer=setInterval(function () { arrowRight.click(); },1000); })
11, 節流閥
①防止輪播圖按鈕連續點擊造成播放過快
②節流閥的目的:當上一個函數動畫內容執行完畢,再去執行下一個函數動畫,讓事件無法連 續觸發
③核心實現思路:利用回調函數,添加一個變量來控制,鎖住函數和解鎖函數
④開始設置一個 var flage=trur;
⑤ if ( flag) { flag=false ; do something } 關閉水龍頭
⑥利用回調函數,動畫執行完畢, flag = true 打開水龍頭
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠標經過,左右按鈕顯示,鼠標離開,左右按鈕隱藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; clearInterval(timer); }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; timer=setInterval(function () { arrowRight.click(); },1000); }) //2,動態生成小圓圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //記錄當前小圓圈的索引號,通過自定義屬性來做 ol.appendChild(li); //3,小圓圈的排他思想,我們可以直接在生成小圓圈的同時直接綁定點擊事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,點擊小圓圈,移動圖片,當然移動的是 ul ,ul 的移動距離=小圓圈的索引號乘以圖片的寬度,注意是負值 var index=this.getAttribute("index");//當我們點擊了某個小 li ,就拿到當前小 li 的索引號 //var sliderWidth=slider.offsetWidth; 下面右側按鈕點擊事件也用到這個值,所以把它放到最上面 num=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給 num circle=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,點擊右側按鈕,圖片滾動一張 var imgLast=ul.children[0].cloneNode(true); //克隆第一張圖片 ul.appendChild(imgLast); var num=0; var circle=0; var flag=true; //flag節流閥 arrowRight.addEventListener("click",function () { if (flag) { flag=false; //關閉節流閥 if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth,function () { flag=true; }); //6,點擊右側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle++; if (circle==ol.children.length) { circle=0; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange(); } }) //7,點擊左側按鈕,圖片滾動一張 arrowLeft.addEventListener("click",function () { if (flag) { flag=false; if (num==0) { // ul.style.left = -(ul.children.length - 1)*sliderWidth + "px"; // num = ul.children.length - 1; num=ul.children.length-1; ul.style.left= -num*sliderWidth +"px"; } num--; animate(ul,-num*sliderWidth,function () { flag=true; }); //8,點擊左側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle--; if (circle<0) { circle=ol.children.length-1; } // for(var i=0;i<ol.children.length;i++) // { // ol.children[i].className=""; // } // ol.children[circle].className="current"; circleChange() } }) function circleChange() { for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; } //9,自動播放輪播圖 var timer=setInterval(function () { arrowRight.click(); },1000); })
12,完整代碼:
①index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="index.css"> <script type="text/javascript" src="animate.js"></script> <script type="text/javascript" src="index.js"></script> </head> <body> <div class="slider"> <a href="javascript:;" class="arrow-left"><</a> <!--左側按鈕--> <a href="javascript:;" class="arrow-right">></a> <!--右側按鈕--> <ul> <li><a href=""><img src="images/01.jpg" alt=""></a></li> <li><a href=""><img src="images/02.jpg" alt=""></a></li> <li><a href=""><img src="images/03.jpg" alt=""></a></li> <li><a href=""><img src="images/04.jpg" alt=""></a></li> </ul> <ol class="circle"></ol> </div> </body> </html>
②index.css
*{ padding:0; margin:0; } a{ text-decoration:none; } ul, ol{ list-style:none; } .slider{ width:721px; height:455px; background-color:purple; margin: 100px auto; position:relative; overflow: hidden; } .slider > ul{ position:absolute; top:0; left:0; width:600%; } .slider > ul >li{ float:left; } .arrow-left, .arrow-right{ width:24px; height:40px; background-color: rgba(0,0,0,0.3); position:absolute; top:50%; margin-top:-20px; z-index:2; text-align:center; line-height:40px; color:#fff; font-size:20px; display:none; } .arrow-left{ left:0; } .arrow-right{ right:0; } ol.circle{ position:absolute; bottom:10px; left:50px; } .circle > li{ float:left; width:8px; height:8px; border:2px solid rgba(255,255,255,0.5); margin:0 3px; border-radius:50%; cursor:pointer; } .current{ background-color: #fff; }
③index.js
window.addEventListener("load",function(){ // alert(11); var slider=document.querySelector(".slider"); var arrowLeft=document.querySelector(".arrow-left"); var arrowRight=document.querySelector(".arrow-right"); var sliderWidth=slider.offsetWidth; //1,鼠標經過,左右按鈕顯示,鼠標離開,左右按鈕隱藏 slider.addEventListener("mouseover",function(){ arrowLeft.style.display= "block"; arrowRight.style.display= "block"; clearInterval(timer); }) slider.addEventListener("mouseout",function(){ arrowLeft.style.display= "none"; arrowRight.style.display= "none"; timer=setInterval(function () { arrowRight.click(); },1000); }) //2,動態生成小圓圈 var ul=document.querySelector("ul"); var imgs=ul.children; var ol=document.querySelector(".circle"); for(var i=0;i<imgs.length;i++) { var li=document.createElement("li"); li.setAttribute("index",i); //記錄當前小圓圈的索引號,通過自定義屬性來做 ol.appendChild(li); //3,小圓圈的排他思想,我們可以直接在生成小圓圈的同時直接綁定點擊事件 li.addEventListener("click",function () { for(var j=0;j<ol.children.length;j++){ ol.children[j].className=""; } this.className = "current"; //4,點擊小圓圈,移動圖片,當然移動的是 ul ,ul 的移動距離=小圓圈的索引號乘以圖片的寬度,注意是負值 var index=this.getAttribute("index");//當我們點擊了某個小 li ,就拿到當前小 li 的索引號 //var sliderWidth=slider.offsetWidth; 下面右側按鈕點擊事件也用到這個值,所以把它放到最上面 num=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給 num circle=index; //當我們點擊了某個小圓圈,就要把這個小圓圈的索引號給circle animate(ul,-index*sliderWidth); }) } ol.children[0].className="current"; //5,點擊右側按鈕,圖片滾動一張 var imgLast=ul.children[0].cloneNode(true); //克隆第一張圖片 ul.appendChild(imgLast); var num=0; var circle=0; var flag=true; //flag節流閥 arrowRight.addEventListener("click",function () { if (flag) { flag=false; //關閉節流閥 if (num==ul.children.length-1) { ul.style.left=0; num=0; } num++; animate(ul,-num*sliderWidth,function () { flag=true; }); //6,點擊右側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle++; if (circle==ol.children.length) { circle=0; } circleChange(); } }) //7,點擊左側按鈕,圖片滾動一張 arrowLeft.addEventListener("click",function () { if (flag) { flag=false; if (num==0) { num=ul.children.length-1; ul.style.left= -num*sliderWidth +"px"; } num--; animate(ul,-num*sliderWidth,function () { flag=true; }); //8,點擊左側按鈕,小圓圈跟隨一起變化,可以再聲明一個變量控制小圓圈的播放 circle--; if (circle<0) { circle=ol.children.length-1; } circleChange() } }) function circleChange() { for(var i=0;i<ol.children.length;i++) { ol.children[i].className=""; } ol.children[circle].className="current"; } //9,自動播放輪播圖 var timer=setInterval(function () { arrowRight.click(); },1000); })
④animate.js
function animate(obj, target, callback) { // console.log(callback); callback = function() {} 調用的時候 callback() // 先清除以前的定時器,只保留當前的一個定時器執行 clearInterval(obj.timer); obj.timer = setInterval(function() { // 步長值寫到定時器的里面 // 把我們步長值改為整數 不要出現小數的問題 // var step = Math.ceil((target - obj.offsetLeft) / 10); var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止動畫 本質是停止定時器 clearInterval(obj.timer); // 回調函數寫到定時器結束里面 // if (callback) { // // 調用函數 // callback(); // } callback && callback(); } // 把每次加1 這個步長值改為一個慢慢變小的值 步長公式:(目標值 - 現在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }