原理
圖片輪播原理:
將一系列大小相等的圖片平鋪,利用css布局只顯示一張圖片,其他圖片隱藏,通過計(jì)算偏移量利用定時(shí)器自動(dòng)切換圖片,或者手動(dòng)點(diǎn)擊切換圖片。
樣式布局
關(guān)于圖片列表的布局,這里在js中使用style.left
這個(gè)屬性計(jì)算偏移量來進(jìn)行圖片的切換。而在style.left
這個(gè)屬性中,是無法識(shí)別樣式表中寫的left值,只對(duì)HTML中寫的left值有效.
關(guān)于小圓點(diǎn)按鈕,使用自定義屬性index
來標(biāo)識(shí)第幾個(gè)小圓點(diǎn)。后邊當(dāng)點(diǎn)擊某個(gè)小圓點(diǎn)時(shí),可獲取該小圓點(diǎn)的index值來知道小圓點(diǎn)的位置。利用css樣式使class="on"
的元素顏色變亮,即點(diǎn)亮當(dāng)前點(diǎn)擊到的小圓點(diǎn)。
關(guān)于箭頭切換,使用鏈接形式,可以添加hover
偽類變換樣式。<
左箭頭;>
右箭頭,html轉(zhuǎn)義字符。
無縫切換:最后一張圖片切換到第一張圖片時(shí),會(huì)出現(xiàn)一片空白,這里,借助兩張輔助圖來填補(bǔ)這片空白。
即將最后一張圖片屬性復(fù)制到第一張圖片前,將第一張圖片屬性信息復(fù)制到最后一張圖片后面。
并且,將第一張圖片輔助圖(實(shí)際上是實(shí)際顯示的第5張圖片隱藏起來,故設(shè)置style="left: -600px;"
)
<div id="container" >
<!-- 圖片列表 -->
<div id="list" style="left: -600px">
<!-- 第一張輔助圖 -->





<!-- 第二張輔助圖 -->
</div>
<!-- 小圓點(diǎn)按鈕 -->
<div id="buttons">
<span index="1" class="on"></span>
<span index="2"></span>
<span index="3"></span>
<span index="4"></span>
<span index="5"></span>
</div>
<!-- 箭頭切換 -->
<a href="javascript:;" class="arrow" id="prev"><</a>
<a href="javascript:;" class="arrow" id="next">></a>
</div>
css結(jié)構(gòu):
- 絕對(duì)定位問題,圖片和原點(diǎn)的浮動(dòng)屬性;
-
overflow: hidden;
//溢出隱藏 - 確保每個(gè)小圓點(diǎn)所在層置頂,(z-index:999;)這里設(shè)置為
z-index:2; 另外
z-index 僅能在定位元素上奏效 -
cursor
CSS屬性定義鼠標(biāo)指針懸浮在元素上方顯示的鼠標(biāo)光標(biāo)。cursor: pointer
顯示為小手。
*{
margin: 0;
padding: 0;
text-decoration: none;
}
body{
padding: 10px;
}
#container{
width: 600px;
height: 400px;
border: 3px solid #333;
overflow: hidden;//溢出隱藏
position: relative;//定位
}
#list{
width: 4200px;//所有圖片平鋪的寬度
height: 400px;
border: 3px solid #333;
position: absolute;//定位問題 利用偏移量進(jìn)行切換
/*z-index: 1;*/
/* transition:left 2s;
-moz-transition:left 2s; Firefox 4
-webkit-transition:left 2s; Safari and Chrome
-o-transition:left 2s; Opera */
}
#list img{
float: left;//浮動(dòng)(不用清除浮動(dòng))
}
#buttons{
position: absolute;
/*height: 20px;
width: 100px*/
/*z-index: 2;*/ //層級(jí),使按鈕置于頂層
bottom: 25px;
left: 250px;
}
#buttons span{
cursor: pointer;/*小手*/
float: left;//浮動(dòng)
border: 1px solid #fff;//白邊框
width: 20px;
height: 20px;
border-radius: 50%;//圓角
background: #333;//黑色
margin-right: 5px;
}
#buttons .on{
background: orangered;//點(diǎn)亮成橘色
}
.arrow{
cursor: pointer;
display: none;//默認(rèn)不顯示箭頭
line-height: 39px;//垂直居中
text-align: center;//水平居中
font-size: 36px;
font-weight: bold;
width: 40px;
height: 40px;
position: absolute;//絕對(duì)定位
/*z-index: 2;*/
top: 180px;//高度
background-color: rgba(0,0,0,0.3);
color: #fff;
}
.arrow:hover{
background-color: rgba(0,0,0,0.7);//鼠標(biāo)移上去顏色加深
}
#container:hover .arrow{
display: block;//鼠標(biāo)移到盒子上顯示箭頭
}
#prev{
left: 20px;//單獨(dú)定義左箭頭水平位置
}
#next{
right: 20px;//單獨(dú)定義右箭頭水平位置
}
js部分整個(gè)功能封裝在window.onload
事件中。
箭頭切換&無限滾動(dòng)&動(dòng)畫切換
先獲取元素,添加點(diǎn)擊事件。parseInt
將字符串轉(zhuǎn)換成數(shù)字。
獲取style.left
,是相對(duì)左邊獲取距離,且style.left
獲取的是字符串,需要用parseInt()取整轉(zhuǎn)化為數(shù)字。
next.onclick=function(){
list.style.left=parseInt(list.style.left)-600+'px';
}
prev.onclick=function(){
list.style.left=parseInt(list.style.left)+600+'px';
}
封裝在函數(shù)animate
里。并實(shí)現(xiàn)循環(huán)切換。當(dāng)切換到第一張輔助圖上時(shí),parseInt(list.style.left)
的值為0,實(shí)際上應(yīng)該是最后一張圖片,所以歸為到最后一張圖片的位置上list.style.left=-3000+'px';
同理,當(dāng)切換到第二張輔助圖上時(shí),parseInt(list.style.left)
的值為-3600,實(shí)際上應(yīng)該是第一張圖片,所以歸為到第一張圖片的位置上list.style.left=-600+'px';
//切換圖片,利用圖片的偏移量
function animate(offset){
var newLeft = parseInt(list.style.left)+offset;//值 圖片左側(cè)距離父元素的值
list.style.left=newLeft+'px';//px
// list.style.left=list.offsetLeft+offset+'px';
if(newLeft>-600){//和第一張圖片位置比較
list.style.left=-3000+'px';//歸位到第五張圖片
}
if(newLeft<-3000){//和最后一張圖片位置比較
list.style.left=-600+'px';//歸位到第一張圖片
}
// debugger;
}
實(shí)現(xiàn)每次切換圖片的過程中,是過渡動(dòng)畫切換的。
思路:通過自定義位移完一張圖片的總時(shí)間time
和每次位移的時(shí)間inteval
,來計(jì)算圖片移動(dòng)一下的距離speed
,直到一張圖片完整的移到當(dāng)前可視的盒子區(qū)域。
在animate()
函數(shù)內(nèi)定義go()
函數(shù),首先判斷圖片是往哪個(gè)方向移,因?yàn)槿绻蜃笠频脑挘磦魅氲钠屏渴秦?fù)值,所以speed < 0
,這時(shí)候圖片左側(cè)距離父元素的值parseInt(list.style.left)
是越來越小的,直到為newLeft
,結(jié)束動(dòng)畫位移,一張圖片完整的切換到了可視區(qū)域。so只要parseInt(list.style.left) >newLeft
,就進(jìn)行動(dòng)畫位移;
同理,當(dāng)圖片向右移時(shí),speed >0
,這時(shí)候圖片左側(cè)距離父元素的值parseInt(list.style.left)
是越來越大的,直到為newLeft
。所以只要parseInt(list.style.left) < newLeft
,就進(jìn)行著動(dòng)畫位移。
如果滿足動(dòng)畫位移條件會(huì)一直執(zhí)行,使用定時(shí)器setTimeout(go, inteval)
,沒隔一段時(shí)間interval
執(zhí)行一次go
。
這里使用了遞歸,函數(shù)內(nèi)部調(diào)用該函數(shù)。
對(duì)于定時(shí)器,注意setInterval()跟setTimeout()的區(qū)別。簡單來說,setInterval()執(zhí)行多次,setTimeout()只執(zhí)行一次。
更具體的用法可以點(diǎn)擊鏈接查看區(qū)別:window.setInterval window.setTimeout 。
這里定義一個(gè)初始值var animated = false;
,表示默認(rèn)不進(jìn)行動(dòng)畫位移,animated = true
表示開始動(dòng)畫位置標(biāo)志。并在結(jié)束動(dòng)畫位移操作時(shí),將animated
的值置為false。
function animate (offset) {
animated = true;//開始動(dòng)畫位移
var time = 300;//一張圖片位移總時(shí)間
var inteval = 10;//位移間隔時(shí)間
var speed = offset/(time/inteval);//求得一次位移的距離
var newLeft = parseInt(list.style.left) + offset;//圖片左側(cè)距離父元素的值
//動(dòng)畫函數(shù)
var go = function (){
//監(jiān)測(cè)是否具備進(jìn)行動(dòng)畫位移的條件
//判斷左切換和右切換兩種情況,都并且一張圖片沒有完整的占滿盒子區(qū)域時(shí)。
if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) >newLeft)) {
list.style.left = parseInt(list.style.left) + speed + 'px';
setTimeout(go, inteval);//遞歸
}else {
list.style.left = newLeft + 'px';
if(newLeft>-600){
list.style.left=-3000+'px';//歸位到第五張圖片
}
if(newLeft<-3000){
list.style.left=-600+'px';//歸位到第一張圖片
}
// debugger;
animated = false;//結(jié)束動(dòng)畫位移
}
}
go();//函數(shù)調(diào)用
}
優(yōu)化:加入下面代碼,當(dāng)傳入的偏移量為0時(shí),animate()函數(shù)里面的部分不需再執(zhí)行了。
if (offset == 0) {
return;
}
按鈕切換
先設(shè)置初始值index
的值為1.即默認(rèn)第一個(gè)小圓點(diǎn)時(shí)點(diǎn)亮著的,index
用來標(biāo)識(shí)第幾個(gè)小圓點(diǎn)。點(diǎn)擊箭頭時(shí)增加或者減小index
的值來實(shí)現(xiàn)切換小圓點(diǎn)的功能。注意index的取值是1~5,所以當(dāng)index的值加到5時(shí),要回歸到1;index的值為1時(shí),要切到5.
實(shí)現(xiàn)思路:先判斷index的值,右箭頭觸發(fā)點(diǎn)擊事件里如果當(dāng)前index的值為5,就使index=1
,否則index+=1;
,同理,左箭頭觸發(fā)點(diǎn)擊事件里如果當(dāng)前index的值為1,就使index=5
,否則index-=1;
然后點(diǎn)亮相應(yīng)的小圓點(diǎn)showButton()
var index = 1;
next.onclick=function(){
animate(-600);
if(index==5){
index=1;//使index的值不超過5
}else{
index+=1;//index的值隨著箭頭的點(diǎn)擊進(jìn)行更新
}
showButton();
}
prev.onclick=function(){
animate(600);
if(index==1){
index=5;//使index的值不小于1
}else{
index-=1;
}
showButton();
}
優(yōu)化:在兩個(gè)點(diǎn)擊事件中先加入以下代碼。當(dāng)檢測(cè)到animated=true
即進(jìn)行著動(dòng)畫位移,不執(zhí)行其他代碼,避免卡頓優(yōu)化性能。
if (animated) {
return;
}
獲取小圓點(diǎn)var buttons = document.getElementById('buttons').getElementsByTagName('span');
,不止一個(gè),是一個(gè)數(shù)組類型。數(shù)組從0開始,所以index -1
.
因?yàn)閏ss樣式中#buttons .on{background: orangered;}
,所以這里利用className= 'on'
來點(diǎn)亮小圓點(diǎn)。
//點(diǎn)亮小圓點(diǎn)
function showButton(){
buttons[index -1].className = 'on';//點(diǎn)亮
}
這樣會(huì)出現(xiàn)一個(gè)問題,切換到下一個(gè)小圓點(diǎn)時(shí),前面點(diǎn)擊過的小圓點(diǎn)依然是點(diǎn)亮著的。所有在showButton()
函數(shù)中要先清除之前的樣式。
for(var i=0;i<buttons.length;i++){//遍歷
if(buttons[i].className=='on'){//關(guān)閉其他亮著的小圓點(diǎn)
buttons[i].className='';
// break;//一旦監(jiān)測(cè)到就退出循環(huán)
}
}
這樣就實(shí)現(xiàn)了點(diǎn)擊箭頭切換圖片時(shí),對(duì)應(yīng)的小圓點(diǎn)也跟著進(jìn)行切換。
===
下面實(shí)現(xiàn)點(diǎn)擊小圓點(diǎn)時(shí),圖片切換的功能
(思路:仍然是利用圖片偏移量進(jìn)行切換,偏移值為-600乘以要點(diǎn)擊的小圓點(diǎn)的index值減去當(dāng)前小圓點(diǎn)的index值)
因?yàn)橐獙?duì)每一個(gè)小圓點(diǎn)添加點(diǎn)擊事件,先對(duì)其進(jìn)行遍歷。
首先獲取要點(diǎn)擊的(目標(biāo))小圓點(diǎn)的自定義屬性值parseInt(this.getAttribute('index'))
,即在html布局中span標(biāo)簽里index的屬性。
getAttribute()
既可以獲取自定義屬性值也可以獲取原本就存在的屬性的值。
不要忘記更新當(dāng)前的index值index=myIndex;
//點(diǎn)擊小圓點(diǎn)進(jìn)行切換圖片
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick = function(){//對(duì)每個(gè)小圓點(diǎn)添加點(diǎn)擊事件
var myIndex = parseInt(this.getAttribute('index'));//獲取要點(diǎn)擊的小圓點(diǎn)的自定義index屬性值
console.log(myIndex);
var offset = -600*(myIndex-index);//求偏移值
animate(offset);
index=myIndex;//更新到當(dāng)前的index值
showButton();
}
// debugger;
}
優(yōu)化:在每個(gè)小圓點(diǎn)的點(diǎn)擊事件中加入以下代碼。
點(diǎn)擊小圓點(diǎn)時(shí),當(dāng)檢測(cè)到animated=true
即進(jìn)行動(dòng)畫位移的過程中,不觸發(fā)該點(diǎn)擊事件即不執(zhí)行后面代碼,避免卡頓優(yōu)化性能。
當(dāng)檢測(cè)到this.className=='on'
即點(diǎn)擊當(dāng)前的小圓點(diǎn),也不需要執(zhí)行后面代碼,優(yōu)化性能。
if (animated) {
return;
}
if(this.className=='on'){
return;
}
自動(dòng)播放
利用定時(shí)器setTimeout()
或setInterval
,實(shí)現(xiàn)每隔3秒自動(dòng)播放下一張圖片。并在鼠標(biāo)移到var container = document.getElementById('container');
上時(shí)清楚浮動(dòng)。
用到一種回調(diào)函數(shù)的使用方式,如果stop(),stop方法就被執(zhí)行了,但是如果寫方法名stop,是事件觸發(fā)時(shí)才會(huì)調(diào)用stop方法
var interval = 3000;
var timer;
function play() {
timer = setTimeout(function () {
next.onclick();
play();
}, interval);
}
function stop() {
clearTimeout(timer);
}
/*
//每隔3秒自動(dòng)播放下一張圖片
function play(){
timer = setInterval(function(){
next.onclick();
},3000);
}
//清除定時(shí)器
function stop(){
clearInterval(timer);
}
*/
container.onmouseover = stop;
container.onmouseout = play;
play();
最后,如果不進(jìn)行一些優(yōu)化,可能會(huì)出現(xiàn)瘋狂點(diǎn)擊會(huì)使圖片錯(cuò)位等情況。