0.最終效果預(yù)覽
基本功能
- 自動(dòng)無(wú)縫滾動(dòng)
- 左右按鈕控制滾動(dòng)
- 點(diǎn)擊圓點(diǎn)切換圖片
1.整體結(jié)構(gòu)與思路
Html部分
<body>
<div id= "parent">
<div id="uls">
<ul id="img_ul">
<li><img src="imgs/0.jpg"/></li>
<li><img src="imgs/1.jpg"/></li>
<li><img src="imgs/2.jpg"/></li>
<li><img src="imgs/3.jpg"/></li>
<li><img src="imgs/4.jpg"/></li>
</ul>
<ul id='litCir_ul'></ul>
</div>
<div id="buttons">
<span id="left"><</span>
<span id="right">></span>
</div>
</div>
</body>
三個(gè)div,最外層id為parent
的大div內(nèi)包含了uls
和buttons
兩個(gè)div予颤,divuls
中包含了兩個(gè)列表img_ul
(圖片列表), litCir_ul
(小圓點(diǎn)列表)涝婉,divbuttons
里則包含了“左”劲件, “右”兩個(gè)按鈕未巫。
CSS部分
#parent{
position: relative;
margin: 50px auto;
padding: 0;
width: 500px;
height: 309px;
}
#uls{
position: relative;
margin: 0;
padding: 0;
width: 500px;
height: 309px;
overflow: hidden;
}
#img_ul{
position: absolute;
margin: 0;
padding: 0;
left: 0;
top: 0;
width: 3000px; /*多留出一張圖片的寬度!*/
list-style: none;
}
#img_ul li{
float: left;
margin: 0;
padding: 0;
width: 500px;
height: 309px;
}
#img_ul li img{
width: 500px;
height: 309px;
}
#litCir_ul{
position: absolute;
margin: 0;
padding: 0;
right: 10px;
bottom: 10px;
list-style: none;
}
#litCir_ul li{
margin: 0;
padding: 0;
float: left;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
border-radius: 50%;
margin-left:10px ;
cursor: pointer;
}
li.active{
background-color: white;
}
li.quiet{
background-color: #1e90ff;
}
#buttons{
margin: 0;
padding: 0;
display: none;
}
#buttons span{
position: absolute;
width: 40px;
height: 40px;
top: 50%;
margin-top: -20px;
line-height: 40px;
text-align: center;
font-weight: bold;
font-family: Simsun;
font-size: 30px;
border: 1px solid #fff;
opacity: 0.3;
cursor: pointer;
color: #fff;
background: black;
}
#left{
left: 5px;
}
#right{
left: 100%;
margin-left: -45px;
}
需要注意的地方
- 圖片的寬蔗草,高度應(yīng)和
img_ul
中的li
標(biāo)簽咒彤, 以及div#parent
疆柔, div#uls
的寬,高度一致镶柱。 -
img_ul
的寬度應(yīng)為(圖片數(shù)目+1)*每張圖片的寬度旷档。也就是要多留出一張圖片的寬度(下一部分解釋)。 - div
uls
部分使用overflow:hidden
隱藏img_ul
超出的部分歇拆,確保每次該區(qū)域只能顯示一張完整的圖片鞋屈。
2.功能實(shí)現(xiàn)(JS部分)
①將會(huì)在下面用到的Html中的對(duì)象和一些變量
/*獲取HTML中的對(duì)象*/
var parent = document.getElementById("parent");
var img_ul = document.getElementById("img_ul");
var litCir_ul = document.getElementById("litCir_ul");
var buttons = document.getElementById("buttons");
var cLis =litCir_ul.children;
var len = img_ul.children.length; //圖片張數(shù)
var width = parent.offsetWidth; //每張圖片的寬度
var rate = 15; //一張圖片的切換速度, 單位為px
var times = 1; //切換速度的倍率
var gap = 2000; //自動(dòng)切換間隙故觅, 單位為毫秒
var timer = null; //初始化一個(gè)定時(shí)器
var picN = 0; //當(dāng)前顯示的圖片下標(biāo)
var cirN = 0; //當(dāng)前顯示圖片的小圓點(diǎn)下標(biāo)
var temp;
②添加小圓點(diǎn)
之所用js添加小圓點(diǎn)厂庇,是因?yàn)樾A點(diǎn)的數(shù)量是由圖片張數(shù)決定的。
for (var i=0; i<len; i++){
var a_li = document.createElement("li");
a_li.className = 'quiet';
litCir_ul.appendChild(a_li);
}
litCir_ul.children[0].className = "active";
默認(rèn)li
的class
為quiet
, 第一張默認(rèn)為active
输吏。
③無(wú)縫滾動(dòng)是怎么實(shí)現(xiàn)的权旷?
首先先理解該輪播圖如何滾動(dòng),這里是通過(guò)控制img_ul
的left
值來(lái)控制顯示某張圖片评也, 為了實(shí)現(xiàn)“滾動(dòng)”的效果炼杖,我們需要逐漸改變img_ul
的left
值灭返,而不能直接使該值變化圖片寬度的倍數(shù)盗迟。這里我們定義一個(gè)動(dòng)畫效果函數(shù)Roll()
。
function Roll(distance){ //參數(shù)distance:滾動(dòng)的目標(biāo)點(diǎn)(必為圖片寬度的倍數(shù))
clearInterval(img_ul.timer); //每次運(yùn)行該函數(shù)必須清除之前的定時(shí)器熙含!
var speed = img_ul.offsetLeft < distance ? rate : (0-rate); //判斷圖片移動(dòng)的方向
img_ul.timer = setInterval(function(){ //設(shè)置定時(shí)器罚缕,每隔10毫秒,調(diào)用一次該匿名函數(shù)
img_ul.style.left = img_ul.offsetLeft + speed + "px"; //每一次調(diào)用滾動(dòng)到的地方 (速度為 speed px/10 ms)
var leave = distance - img_ul.offsetLeft; //距目標(biāo)點(diǎn)剩余的px值
/*接近目標(biāo)點(diǎn)時(shí)的處理怎静,滾動(dòng)接近目標(biāo)時(shí)直接到達(dá)邮弹, 避免rate值設(shè)置不當(dāng)時(shí)不能完整顯示圖片*/
if (Math.abs(leave) <= Math.abs(speed)) {
clearInterval(img_ul.timer);
img_ul.style.left = distance + "px";
}
},10);
}
試想下面的情況,當(dāng)圖片從最后一張切換到第一張時(shí)蚓聘,這時(shí)就不能通過(guò)逐漸改變img_ul
的left
值來(lái)實(shí)現(xiàn)滾動(dòng)的效果腌乡,于是克隆第一張圖片至列表尾部,當(dāng)滾動(dòng)完最后一張圖片時(shí)夜牡,繼續(xù)滾動(dòng)到克隆的第一張与纽,然后將img_ul
的left
值置為0。
/*克隆第一個(gè)li到列表末*/
img_ul.appendChild(img_ul.children[0].cloneNode(true));
④自動(dòng)滾動(dòng)
function autoRun(){
picN++;
cirN++;
if(picN > len){ //滾動(dòng)完克隆項(xiàng)后
img_ul.style.left = 0; //改變left至真正的第一項(xiàng)處
picN = 1; //從第二張開始顯示
}
Roll(-picN*width);
if(cirN > len-1){ //判斷是否到了最后一個(gè)圓點(diǎn)
cirN = 0;
}
for(var i=0; i<len; i++){
cLis[i].className = "quiet";
}
cLis[cirN].className = "active";
}
需要注意的是小圓點(diǎn)和圖片列表的li
數(shù)目是不一樣的塘装,當(dāng)滾動(dòng)到最后一個(gè)克隆項(xiàng)時(shí)急迂,此時(shí)小圓點(diǎn)實(shí)際上在第一個(gè)位置。
開始自動(dòng)滾動(dòng):
timer = setInterval(autoRun, gap);
⑤觸及小圓點(diǎn)時(shí)切換至對(duì)應(yīng)圖片
for(var i=0; i<len; i++){
cLis[i].index = i;
cLis[i].onmouseover = function(){
for(var j=0; j<len; j++){
cLis[j].className = "quiet";
}
this.className = "active";
temp = cirN;
picN = cirN = this.index;
times = Math.abs(this.index - temp); //距離上個(gè)小圓點(diǎn)的距離
rate = rate*times; //根據(jù)距離改變切換速率
Roll(-this.index * width);
rate = 15;
}
}
給每個(gè)小圓點(diǎn)綁定了onmouseover事件蹦肴,這個(gè)方法有個(gè)細(xì)節(jié)僚碎,會(huì)根據(jù)兩次小圓點(diǎn)的距離差調(diào)整速率為rate*times
,使切換效果更自然(也就是說(shuō)每次切換說(shuō)花的時(shí)間基本一致阴幌,無(wú)論是第一張到第二張勺阐,還是第一張到最后一張)卷中。
⑥觸及輪播圖區(qū)域和離開該區(qū)域時(shí)
parent.onmouseover = function(){
clearInterval(timer);
buttons.style.display = 'block';
}
parent.onmouseout = function(){
timer = setInterval(autoRun, gap);
buttons.style.display = 'none';
}
觸及區(qū)域,清除定時(shí)器皆看,顯示按鈕仓坞。
離開區(qū)域,添加定時(shí)器腰吟,隱藏按鈕无埃。
⑦給兩個(gè)按鈕添加onclick事件
/*上一張*/
buttons.children[0].onclick = function(){
picN--;
cirN--;
if(picN < 0){ //滾動(dòng)完第一項(xiàng)后
img_ul.style.left = -len*width + "px"; //改變left至克隆的第一項(xiàng)處
picN = cirN = len-1;
}
Roll(-picN*width);
//bug處理
if(cirN < 0){
cirN = len-1;
}
for(var i=0; i<len; i++){
cLis[i].className = "quiet";
}
cLis[cirN].className = "active";
}
/*下一張*/
buttons.children[1].onclick = autoRun;
自動(dòng)播放就是間隔一定時(shí)間不斷調(diào)用函數(shù)“下一張”的過(guò)程,所以這里的按鈕right
下一張的實(shí)現(xiàn)就是上面的autoRun
函數(shù)毛雇。
以上就是輪播圖各部分的實(shí)現(xiàn)原理嫉称,如果你有其他的方法,歡迎一起交流灵疮!
2019.3.30更新:
用requestAnimationFrame()實(shí)現(xiàn)一個(gè)輪播圖