1、寫在最前面javascript
最近都忙一些雜七雜八的事情,複習軟考、研讀經典...好像都很久沒寫過博客了。。。css
我本身寫過三個圖片輪播,一個是簡單的原生JS實現的,沒有什麼動畫效果的,一個是結合JQuery實現的,淡入淡出切換的。如今想作一個酷一點的放在博客或者我的網站,到時候能夠展現本身的做品。逛了一下慕課網,發現有個旋轉木馬的jquery插件課程,有點酷酷的,因而就想着用原生JS封裝出來。作起來才發現,沒有本身想象中的那麼容易。。。不囉嗦了,講解一下實現過程吧。html
2、效果java
因爲本身的服務器還沒弄好。在線演示不了(ORZ...)。。。只能放一張效果圖了。。。node
從圖片上仍是能夠看出大概效果的,我就很少說了。想看真實代碼效果的,歡迎到個人github上面download代碼,別忘了給個人github項目點個星星噢^_^jquery
3、實現過程git
html結構github
<div class="carrousel-main" data-setting='{"width":1000,"height":400, "carrouselWidth":750, "carrouselHeight":400, "scale":0.9, "verticalAlign":"middle"}'> <div class="carrousel-btn carrousel-btn-pre"></div> <ul class="carrousel-list"> <li class="carrousel-item"> <a href="#"><img src="img/1.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/2.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/3.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/4.jpg"></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/5.jpg"></a> </ul> <div class="carrousel-btn carrousel-btn-next"></div> </div>
這個結構和通常輪播的html代碼結構是同樣的,稍有不一樣就是,主輪播div上面有一個data-setting的屬性,這個屬性裏面就是一些輪播效果的參數。參數的具體意義稍後再講解。數組
css部分的代碼就不貼了,最重要就是要注意元素的絕對定位,由效果圖能夠看出來,每張圖片的位置、大小都不同,因此這些都是經過js控制的,所以須要絕對定位。下面重點講一下js實現過程。服務器
JS實現過程
下面講幾個JS的關鍵步驟,作好了這幾個步驟以後,應該就沒有什麼難點了。
①默認參數
既然是封裝插件,那麼確定會有一些參數的默認值須要配置的啦。這個插件中,主要有以下參數:
width:1000, //幻燈片區域的寬度 height:400, //幻燈片區域的高度 carrouselWidth:700, //幻燈片第一幀的寬度 carrouselHeight:400, //幻燈片第一幀的高度 scale:0.9,//記錄顯示比例關係,例如第二張圖比第一張圖顯示的時候寬高小多少 autoPlay:true,//是否自動播放 timeSpan:3000,//自動播放時間間隔 verticalAlign:'middle' //圖片對齊方式,有top\middle\bottom三種方式,默認爲middle
②封裝對象
由於一個網站可能有多個地方都會用到同一個輪播插件,因此封裝很關鍵。定義了這個對象以後,若是給對象定義一個初始化方法是能夠建立多個對象的,只須要把全部類相同的dom傳進去就能夠了。因此,個人初始化方法以下:
Carousel.init=function(carrousels){ var _this=this; //將nodeList轉換爲數組 var cals= toArray(carrousels);
/*由於原生JS獲取全部的類,獲得的是一個nodeList,是一個類數組,若是想要使用數組的方法則須要轉化爲真正的數組。這裏toArray爲轉化方法。*/ cals.forEach(function(item,index,array){ new _this(item); }); }
這樣的話,我在window.onload的時候,調用Carrousel.init(document.querySelectorAll('.carrousel-main'));這樣就能夠建立多個輪播啦!
③初始化好第一幀的位置參數
由於,第一幀以後的全部幀的相關參數都是參照第一幀來定義的,所以,定義好第一幀很關鍵。
setValue:function(){ this.carrousel.style.width=this.Settings.width+'px'; this.carrousel.style.height=this.Settings.height+'px'; /*左右按鈕設置,這裏要讓左右按鈕平均地瓜分輪播區域寬減去第一幀寬度以後的區域,z-index要比除第一幀外全部圖片都高,而圖片恰好左右分放置,所以z-index的值就是圖片數量的一半。*/ var btnW=(this.Settings.width-this.Settings.carrouselWidth)/2; this.preBtn.style.width=btnW+'px'; this.preBtn.style.height=this.Settings.height+'px'; this.preBtn.style.zIndex=Math.ceil(this.carrouselItems.length/2); this.nextBtn.style.width=btnW+'px'; this.nextBtn.style.height=this.Settings.height+'px'; this.nextBtn.style.zIndex=Math.ceil(this.carrouselItems.length/2); //第一幀相關設置 this.carrouselFir.style.left=btnW+'px'; this.carrouselFir.style.top=this.setCarrouselAlign(this.Settings.carrouselHeight)+'px'; this.carrouselFir.style.width=this.Settings.carrouselWidth+'px'; this.carrouselFir.style.height=this.Settings.carrouselHeight+'px'; this.carrouselFir.style.zIndex=Math.floor(this.carrouselItems.length/2); },
這裏,就是new對象的時候,就到dom結點中獲取data-setting參數,而後更新默認參數配置。這裏有個地方須要注意的,獲取dom的參數不能直接以賦值的方式更新默認參數,由於用戶配置參數的時候,不必定會全部參數都配置一次。若是直接賦值而用戶恰好不是全部參數都配置的話就會形成參數丟失。這裏我是本身寫了一個相似JQuery中的$.extend方法的對象擴展方法來更新參數的。具體就不列舉了,感興趣的能夠去下載。
④其餘圖片位置設置
這裏的圖片實際上就是把除第一張以外的圖片,平均地分到左右兩則,而左邊的圖片位置和右邊的是不一樣的,所以須要分別配置:
//設置右邊圖片的位置關係 var rightIndex=level; rightSlice.forEach(function(item,index,array){ rightIndex--; var i=index; rw=rw*carrouselSelf.Settings.scale;//右邊的圖片是按照scale比例逐漸變小的 rh=rh*carrouselSelf.Settings.scale; item.style.zIndex=rightIndex;//越往右邊z-index的值越小,能夠用圖片數量的通常逐漸遞減 item.style.width=rw+'px'; item.style.height=rh+'px'; item.style.opacity=1/(++i);//越往右邊透明度越小
//這裏的gap計算方法爲:輪播區域減去第一幀寬度,除2,再除左邊或者右邊的圖片張數 item.style.left=(constOffset+(++index)*gap-rw)+'px';//left的值實際上就是第一幀的left+第一幀的寬度+item的間距減去item的寬度 item.style.top=carrouselSelf.setCarrouselAlign(rh)+'px'; });
左邊的設置方法相似且更爲簡單,就不細說了。
⑤旋轉時全部圖片的位置大小調整
這一步很關鍵,點擊右邊按鈕下一張的即爲左旋轉,而點擊左邊按鈕上一張即爲右旋轉。此時,咱們只須要把全部的圖片當作一個環形那樣,點擊一次,換一次位置即完成旋轉。具體爲左旋轉的時候,令第二張的參數等於第一張,第三張等於第二張...而最後一張等於第一張便可。右旋轉的時候,令第一張的參數等於第二張,第二張的參數等於第三張...而最後一張的參數等於第一張便可。
這裏就說說左旋轉吧
if(dir=='left'){ toArray(this.carrouselItems).forEach(function(item,index,array){ var pre; if(index==0){//判斷是否爲第一張 pre=_this.carrouselLat;//讓第一張的pre等於最後一張 var width=pre.offsetWidth; //獲取相應參數 var height=pre.offsetHeight; var zIndex=pre.style.zIndex; var opa=pre.style.opacity; var top=pre.style.top; var left=pre.style.left; }else{ var width = tempWidth; var height = tempHeight; var zIndex = tempZIndex; var opa = tempOpacity; var top = tempTop; var left = tempLeft; } //這裏須要注意,由於第二張圖片是參照第一張的,而這樣改變的時候,第一張是首先被改變的,所以必須先把第一張的相關參數臨時保存起來。 tempWidth = item.offsetWidth; tempHeight = item.offsetHeight; tempZIndex = item.style.zIndex; tempOpacity = item.style.opacity; tempTop = item.style.top; tempLeft = item.style.left; item.style.width=width+'px'; item.style.height=height+'px'; item.style.zIndex=zIndex; item.style.opacity=opa; item.style.top=top; // item.style.left=left; animate(item,'left',left,function(){//自定義的原生js動畫函數 _this.rotateFlag=true; }); }); }
這裏的旋轉,若是不使用一些動畫過分,會顯得很生硬。可是原生JS並無動畫函數,這裏我是本身寫了一個模仿的動畫函數。其原理就是獲取dom原來的樣式值,與新傳入的值比較。用一些方法定義一個速度。我這裏的速度就是用其差值除18.然定義一個計時器,參考了一下jquery源碼裏面的時間間隔爲每13毫秒執行一次。而後才原來的樣式值每次加上speed後等於傳入的值的時候清楚計時器便可。具體能夠看這裏。
好啦,關鍵的地方都差很少啦,若是明白這些過程應該就很容易了!
4、總結思考
總結:
我的感受這仍是一個比較好理解的插件。若是能結合JQuery來作就至關簡單了。可是用原生來寫的話,仍是有一些不那麼流暢的感受。應該是自定義動畫比不上JQuery封裝好的動畫吧。
還有,這個插件由於圖片須要平均分到左右兩邊,因而對於偶數數量的圖片來講,這裏用的方法是克隆第一張,而後加到最後,造成一個奇數。
思考:
若是說有bug的話,那就是我定義了一個rotateFlag的標誌去判斷當前可否旋轉,就是預防快速點擊的時候跟不上。我在按下的時候把rotateFlag設置爲false,而後在動畫結束後再把rotateFlag設置爲true,可是好像做用並不明顯。。。但願有關大神能夠指教一下。。。
本輪播插件下載地址:個人github!