最近看了一組故宮的圖片,以爲很大氣,決定選用故宮的圖片用來展現,以下:javascript
樣式構成與上一節類似,這裏稍作調整,便再也不贅述。css
輪播圖的動畫效果,就是圖片按照規定的方向,不停滾動以展現每一張圖片,同時還能夠經過點擊以改變本來的展現順序。實現有一下幾點:html
圖片自行滾動務必就要使用到定時器setInterval
或者setTimeout
,使得移動函數每隔一段時間執行一次,以達到循環滾動的動畫效果。java
setInterval()
方法會重複調用一個函數或執行一個代碼段,在每次調用之間具備固定的時間延遲,返回一個intervalID
,能夠做爲參數傳給clearInterval()
來取消該定時器。閉包
setTimeout()
方法設置一個定時器,在定時器到期後會執行一個函數或一段代碼,返回值timeoutID
是一個正整數,表示定時器的編號。這個值能夠傳遞給clearTimeout()
來取消該定時器。ide
setInterval( )函數
let intervalID = window.setInterval(func, delay);
複製代碼
intervalID
是此重複操做的惟一辨識符,能夠做爲參數傳給clearInterval()
。func
是你想要重複調用的函數。setTimeout( )動畫
var timeoutID = scope.setTimeout(function, delay); 複製代碼
function
是你想要在delay毫秒以後執行的函數。首先,理解圖片的循環滾動,實際上就是屢次連續的移動,每次移動固定的距離,若干次的移動,就造成了循環效果,那麼此處咱們應該首個實現的是移動一次的效果,即移動函數--movefunc
。ui
咱們先回顧一下各個容器之間的層級關係:spa
<!--最外層的父級容器-->
<div class="imgScroll">
<!--圖片展現區-->
<div class="showContainer">
<div class="container" style="left: 0px;">
<img src="https://dimg02.c-ctrip.com/images/100b11000000qezw729A4_R_1600_10000_Mtg_7.jpg" alt="A cat">
<img src="https://dimg05.c-ctrip.com/images/100u0x000000le38uA71D_R_1600_10000_Mtg_7.jpg" alt="A dog">
<img src="https://dimg08.c-ctrip.com/images/100811000000qrlfxA3E0_R_1600_10000_Mtg_7.jpg" alt="dandelion">
</div>
</div>
<!--底部提示區-->
<div class="dots">
<span class="dot active"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
<!--左右箭頭-->
<div class="left-triangle triangle">
<span><</span>
</div>
<div class="right-triangle triangle">
<span>></span>
</div>
</div>
複製代碼
最外層div.imgScroll
的是整個實現的父容器,其子元素div.showContainer
是展現容器,裏層div.ontainer
是滾動容器,該滾動容器相對於展現容器是絕對定位,那麼移動函數就是要讓滾動容器進行移動,即要改變滾動容器的style.left
屬性。
上面咱們規定,圖片要自右向左滾動,即滾動容器每次向左移動一張圖片的寬度(記變量爲oneImgWidth
)即div.container.style.left
每次減少一個oneImgWidth
。
首先要獲取滾動容器,和它的的初始狀態。原生方法:getElementsByClassName()
和getElementById()
均可以獲取DOM
文檔中的元素,在html
結構中沒有使用id
進行元素表示,則使用前者,可是要注意該方法獲取獲得的是一個元素集合HTMLCollection
,須經過下標的方式獲取第一個元素:
var container = document.getElementsByClassName("container")[0]; //獲取滾動容器
var oldLeftPos = parseInt(container.style.left); //獲取滾動容器的初始狀態,並利用parseInt()方法取整
複製代碼
注意: 在上面的html
結構中,你會注意到有一句行內樣式style="left: 0px;"
,這是爲了防止style.left
取不到值而報錯。
而後獲取圖片的寬度,即爲滾動容器每次移動的步長:
var oneimgWidth = container.children[0].offsetWidth; //這是一個整數
複製代碼
滾動容器左移:
var newLeftPos = oldLeftPos - oneimgWidth;
container.style.left = newLeftPos + "px"; //記得加上單位px
複製代碼
這樣就實現了一次移動效果--移動函數:
function movefunc() {
var container = document.getElementsByClassName("container")[0]; //獲取滾動容器
var oneImgWidth = container.children[0].offsetWidth; //獲取一張圖片的寬度,即每次左移的距離
var oldLeft = parseInt(container.style.left); //獲取滾動容器的初始的左距離,利用parseInt()方法取整
var newLeft = oldLeft - oneImgWidth;
container.style.left = newLeft + "px"; //改變滾動容器的左距離
}
複製代碼
實現了移動函數,咱們開始正真的輪播圖實現的第一步動畫效果——自動循環滾動,前面已經介紹過定時器的基本使用,如今開始利用定時器和移動函數,實現循環移動造成動畫:
建立一個rollAuto()
定時器函數:
function rullAuto() {
setInterval("movefunc()", 800); //每隔800毫秒執行一次移動函數
}
rullAuto(); //須要先執行一次定時器函數,才能夠開始定時器
複製代碼
在輪播圖中不進行任何操做時,圖片會自行滾動,可是當鼠標移動到展現區中時,滾動的圖片則中止滾動,鼠標再移出展現區,則滾動繼續,那麼在這一進一出的兩次操做中,就涉及了兩次對於定時器的不一樣操做,一次清除,一次恢復,其中,移進爲清除,移出爲恢復。
根據上述定時器的介紹,清除定時器須要一個表示須要被清除定時器的編號,咱們使用一個變量timer
來保存該定時器。
var timer = setInterval("movefunc()", 800); //每隔800毫秒執行一次移動函數
clearInterval(timer); //清除使移動函數循環執行的定時器
複製代碼
鼠標的移動會觸發鼠標事件事件,例如此處,鼠標移進會觸發onmouseover
事件,鼠標移出會觸發onmouseout
事件,則咱們能夠爲展現區元素綁定這兩個事件:
var showContainer = document.getElementsByClassName("showContainer")[0]; //獲取展現區元素
//綁定鼠標事件
showContainer.onmouseover = function() {
clearInterval(timer);
};
showContainer.onmouseout = function() {
rullAuto(); //鼠標移出,繼續執行移動函數
};
複製代碼
最後咱們將這個自行滾動函數整理一下:
function autoRullImg() {
var showContainer = document.getElementsByClassName("showContainer")[0];
var timer = null;
function rullAuto() {
timer = setInterval("movefunc()", 800);
}
rullAuto();
showContainer.onmouseover = function() {
clearInterval(timer);
};
showContainer.onmouseout = function() {
rullAuto();
};
}
複製代碼
這樣做爲一個完整的函數就拿過了使用,必定會讓你大失所望,圖片滾着滾着就不見了,container
的style.left
還在不斷減少。你會發現這不是咱們想要的結果。咱們但願的是,當最後一張圖片滾出展現區後,應該出現第一張圖,那麼此處就須要作一個極限條件的判斷。
var container = document.getElementsByClassName("container")[0]; //獲取滾動容器
var imgNum = container.children.length; //獲取圖片數量
var oneImgWidth = container.children[0].offsetWidth; //獲取每張圖的寬度(CSS樣式設置中,每張圖寬帶同樣)
//若是最後一張圖移出展現區,初始化滾動容器的.style.left屬性值
if (parseInt(container.style.left) <= -imgNum * oneImgWidth) {
container.style.left = "0px";
}
複製代碼
最終整合版以下:
function autoRullImg() {
var timer = null;
var showContainer = document.getElementsByClassName("showContainer")[0];
var container = document.getElementsByClassName("container")[0];
var imgNum = container.children.length;
var oneImgWidth = container.children[0].offsetWidth;
function rullAuto() {
timer = setInterval(function(){
movefunc();
if (parseInt(container.style.left) <= -imgNum * oneImgWidth) {
container.style.left = "0px";
}
}, 800);
}
rullAuto();
showContainer.onmouseover = function() {
clearInterval(timer);
};
showContainer.onmouseout = function() {
rullAuto();
};
}
複製代碼
點擊向左箭頭,滾動容器應該向右移動;點擊向右箭頭,滾動容器向左移動,這裏就出現了一個問題,咱們的移動函數,是將container.style.left
減小一個圖片的寬度,即便得圖片向左移動,自行滾動函數和點擊向右箭頭效果與此相同。
可是點擊向左箭頭,則是朝着方向了,所以,咱們以前的移動函數movefunc
就須要改動了,爲了區分兩個函數,咱們現將改進的移動函數改名爲movement()
,再也不僅僅是移動圖片了,如果其餘元素的移動也就能夠重用該函數了。
爲了知足兩個方向的移動,咱們就能夠把移動的步長做爲參數,傳給該函數,函數就能夠根據參數的正負值,進行不一樣方向的移動,以下:
function movement(offset) {
var container = document.getElementsByClassName("container")[0];
var oldLeft = parseInt(container.style.left);
var newLeft = oldLeft + offset;
container.style.left = newLeft + "px";
}
複製代碼
這樣就完成了一個可重用的移動函數,移動步長能夠經過參數控制。在此能夠得出,須要滾動容器向左移動時,就傳進一個負值,反之則爲正值。
那麼,autoRullImg()
函數中就要把本來的移動函數替換爲新的移動函數,並傳一個負值進去:
movement(-oneImgWidth);
複製代碼
一樣在此以前,須要先獲取元素:
var leftTriangle = document.getElementsByClassName("left-triangle")[0]; //左箭頭
var rightTriangle = document.getElementsByClassName("right-triangle")[0]; //右箭頭
複製代碼
在這裏點擊向右箭頭,container
向左移動;點擊向左箭頭,container
向右移動,給左右箭頭綁定點擊事件:
leftTriangle.onclick = function() {
movement(oneImgWidth);
};
rightTriangle.onclick = function() {
movement(-oneImgWidth);
};
複製代碼
一樣,在擊左右箭頭控制圖片移動的時候,也須要進行極限條件的判斷,在點擊向右箭頭的狀況中,若是已是第一張圖再點擊向右箭頭,應該出現的事最後一張圖;再點擊向左箭頭時,若是已經到了最後一張圖,再點擊向右箭頭,應該出現的是第一張圖。
function clickTriangle() {
var container = document.getElementsByClassName("container")[0];
var imgNum = container.children.length;
var oneImgWidth = container.children[0].offsetWidth;
leftTriangle.onclick = function() {
if (parseInt(container.style.left) >= 0) {
container.style.left = -(imgNum - 1) * oneImgWidth + "px";
} else {
movement(oneImgWidth);
}
};
rightTriangle.onclick = function() {
if (parseInt(container.style.left) <= -(imgNum - 1) * oneImgWidth) {
container.style.left = "0px";
} else {
movement(-oneImgWidth);
}
};
}
複製代碼
function clickDots(){
var container = document.getElementsByClassName("container")[0];
var oneImgWidth = container.children[0].offsetWidth;
var dots = document.getElementsByClassName("dots")[0].children; //獲取提示圓點
for(var i = 0; i < dots.length; i++){
(function(n){
dots[n].onclick = function(){
container.style.left = -n*oneImgWidth + "px";
}
})(i);
}
}
複製代碼
由於循環體中使用了循環變量i
,須要使用建立匿名函數並當即執行的方式,解決閉包問題。
到此爲止,已經實現基本需求,圖片自行滾動、鼠標移動到展現區滾動中止、鼠標移出展現區滾動繼續、點擊向左箭頭出現當前展現圖的左邊的圖、點擊向右箭頭出現當前展現的圖片的右邊的圖片、點擊底部提示圓點出現相應圖片。
可是還有一個問題,每次圖片滾動,和點擊左右箭頭,底部的提示圓點並無相應高亮顯示。應該達到的效果是第一張圖顯示時,一個提示圓點應該高亮;第二張圖顯示時,第二個提示圓點要高亮...最後一張圖顯示時,最後一個提示圓點高亮。
所以應該有個記號,用來標記每一次展的示圖片。所以咱們聲明這樣一個記號叫作index
,用來標識當前展現的圖片,其初始狀態爲0
,即展現區顯示第一張圖。
滾動容器div.container
每向左滾動一次,index
就應增長1
,而當index
增長到爲imgNum
時,即最後一張圖剛好左移出展現區時,應該展現第一張圖片,即index
要重置爲0
;滾動容器div.container
向右滾動時,則與此相反。
不管是自行滾動函數,仍是點擊事件函數,都會引發記號index
的變化,因此咱們須要將index
的聲明和初始化,放在這些全部函數的最外層,極限條件的判斷放進每個動畫函數autoRullImg()
、 clickTriangle()
、 clickDots()
裏面:
//點擊向右箭頭
rightTriangle.onclick = function() {
if (parseInt(container.style.left) <= -(imgNum - 1) * oneImgWidth) {
container.style.left = "0px";
} else {
movement(-oneImgWidth);
}
index = index + 1;
if (index > imgNum - 1) {
index = 0;
}
};
//點擊向左箭頭
leftTriangle.onclick = function() {
if (parseInt(container.style.left) >= 0) {
container.style.left = -(imgNum - 1) * oneImgWidth + "px";
} else {
movement(oneImgWidth);
}
index = index - 1;
if (index < 0) {
index = imgNum - 1;
}
};
複製代碼
自行滾動函數修改以下:
function autoRullImg() {
var timer = null;
var showContainer = document.getElementsByClassName("showContainer")[0];
var container = document.getElementsByClassName("container")[0];
var imgNum = container.children.length;
var oneImgWidth = container.children[0].offsetWidth;
function rullAuto() {
timer = setInterval(function(){
index++;
if (index > imgNum - 1) {
index = 0;
}
movement(-oneImgWidth);
if (parseInt(container.style.left) <= -imgNum * oneImgWidth) {
container.style.left = "0px";
}
}, 800);
if (parseInt(container.style.left) <= -imgNum * oneImgWidth) {
container.style.left = "0px";
}
}
rullAuto();
showContainer.onmouseover = function() {
clearInterval(timer);
};
showContainer.onmouseout = function() {
rullAuto();
};
}
複製代碼
有了記號,則須要一個高亮顯示的函數,根據記號index
來讓底部提示圓點高亮顯示,咱們先獲取包含提示圓點的圓點容器,而後獲取他的子元素,即<span class="dot"></span>
小圓點,遍歷這些元素,對比它們的下標,若是和記號index
相同,則改變該提示圓點爲高亮,即添加一個active
類。
function showDots(target) {
var dots = document.getElementsByClassName("dots")[0].children;
for (var i = 0; i < dots.length; i++) {
if (i !== target) {
dots[i].classList.remove("active"); //增長表示高亮的類名
} else {
dots[i].classList.add("active"); //去掉高亮
}
}
}
複製代碼
注意: 因爲點擊底部提示圓點,會使得記號index
有跳動,即不是index
的變化不在1
以內,不只僅是+1
和-1
的變化,這一點須要尤爲注意。自行滾動函數是無限循環執行的,當點擊過底部提示圓點後,記號值倍打亂,因此要將index
值返回出去,以便自行滾動函數能夠獲取:
function clickDots(){
for(var i = 0; i < dots.length; i++){
(function(n){
dots[n].onclick = function(){
container.style.left = -n*oneImgWidth + "px";
index = n;
showDots(index);
}
})(i);
}
return index; //返回記號值
}
複製代碼
如今終於大功告成了,每一部分的功能都已經實現,如今就只須要將全部的函數整合了,別掉以輕心,整合函數依然是一個不可忽視的步驟,這其中你可能會發現一些問題,這些問題將大大下降用戶的體驗。那麼如今來開始整合函數。
爲了不出現全局變量,咱們將全部的函數和變量所有放進一個函數中,聲明此函數名爲slideShow()
,爲實現HTML
文檔加載完就開始執行這個函數,須要使用window.onload()
方法:
window.onload = slideShow;
複製代碼
咱們在多個函數中都重複獲取了DOM
元素,如今咱們把獲取元素放在slideShow()
這個函數的首部:
function autoRullImg() {
var timer = null;
var showContainer = document.getElementsByClassName("showContainer")[0];
var container = document.getElementsByClassName("container")[0];
var imgNum = container.children.length;
var oneImgWidth = container.children[0].offsetWidth;
var leftTriangle = document.getElementsByClassName("left-triangle")[0];
var rightTriangle = document.getElementsByClassName("right-triangle")[0];
var dots = document.getElementsByClassName("dots")[0].children; //獲取提示圓點
var index = 0;
function showDots(target) {
var dots = document.getElementsByClassName("dots")[0].children;
for (var i = 0; i < dots.length; i++) {
if (i !== target) {
dots[i].classList.remove("active"); //增長表示高亮的類名
} else {
dots[i].classList.add("active"); //去掉高亮
}
}
}
function movement(offset) {
var oldLeft = parseInt(container.style.left);
var newLeft = oldLeft + offset;
container.style.left = newLeft + "px";
}
showContainer.onmouseover = function() {
clearInterval(timer);
};
showContainer.onmouseout = function() {
rullAuto();
};
function clickTriangle() {
leftTriangle.onclick = function() {
if (parseInt(container.style.left) >= 0) {
container.style.left = -(imgNum - 1) * oneImgWidth + "px";
} else {
movement(oneImgWidth);
}
index = index - 1;
if( index < 0){ index = imgNum - 1;}
showDots(index);
};
rightTriangle.onclick = function() {
if (parseInt(container.style.left) <= -(imgNum - 1) * oneImgWidth) {
container.style.left = "0px";
} else {
movement(-oneImgWidth);
}
index = index + 1;
if( index > imgNum - 1){ index = 0;}
showDots(index);
};
}
clickTriangle()
function clickDots(){
for(var i = 0; i < dots.length; i++){
(function(n){
dots[n].onclick = function(){
container.style.left = -n*oneImgWidth + "px";
index = n;
showDots(index);
}
})(i);
}
return index;
}
clickDots()
function rullAuto() {
timer = setInterval(function(){
movement(-oneImgWidth);
index = index + 1;
if( index > imgNum - 1){ index = 0;}
showDots(index);
if (parseInt(container.style.left) <= -imgNum * oneImgWidth) {
container.style.left = "0px";
}
}, 2000);
}
rullAuto();
}
window.onload = autoRullImg;
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>img scroll</title>
<link rel="stylesheet" href=".layout.css">
<script src="./scrollImg.js"></script>
</head>
<body>
<div class="imgScroll">
<div class="showContainer">
<div class="container">
<img src="https://dimg02.c-ctrip.com/images/100b11000000qezw729A4_R_1600_10000_Mtg_7.jpg" alt="A cat">
<img src="https://dimg05.c-ctrip.com/images/100u0x000000le38uA71D_R_1600_10000_Mtg_7.jpg" alt="A dog">
<img src="https://dimg08.c-ctrip.com/images/100811000000qrlfxA3E0_R_1600_10000_Mtg_7.jpg" alt="dandelion">
</div>
</div>
<div class="dots">
<span class="dot active"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
<div class="left-triangle triangle">
<span><</span>
</div>
<div class="right-triangle triangle">
<span>></span>
</div>
</div>
</body>
</html>
複製代碼
.imgScroll {
width: 800px;
margin: 0 auto;
position: relative;
}
.imgScroll .showContainer {
width: 800px;
height: 533px;
margin: 0 auto;
overflow: hidden;
position: relative;
}
.imgScroll .showContainer .container {
width: 9999px;
position: absolute;
left: 0px;
}
.imgScroll .showContainer .container img {
display: block;
float: left;
width: 800px;
}
.imgScroll .triangle {
position: absolute;
top: 40%;
cursor: pointer;
font-size: 40px;
color: lightgray;
}
.imgScroll .triangle:hover {
color: gray;
}
.imgScroll .triangle.left-triangle {
left: -50px;
}
.imgScroll .triangle.right-triangle {
right: -50px;
}
.imgScroll .dots {
width: 100%;
text-align: center;
height: 50px;
line-height: 50px;
cursor: pointer;
}
.imgScroll .dots .dot {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
background: lightgray;
margin-right: 10px;
}
.imgScroll .dots .dot.active {
background-color: gray;
}
複製代碼