自己自己寫過三個圖片輪播,一個是簡單的原生JS實現的,沒有什麼動畫效果的,一個是結合JQuery實現的,淡入淡出切換的。現在想做一個酷一點的放在部落格或個人網站,到時候可以展示自己的作品。逛了一下慕課網,發現有個旋轉木馬的jquery插件課程,有點酷酷的,於是就想著用原生JS封裝出來。做起來才發現,沒有自己想像中的那麼容易。 。 。不囉嗦了,講解一下實現過程吧。
二、效果
由於自己的伺服器還沒弄好。線上示範不了(ORZ...),只能放一張效果圖了。
圖片上還是可以看出大概效果的,我就不多說了。想看真實程式碼效果的,歡迎到我的github上面download程式碼,別忘了給我的github專案點個星星噢^_^
三、實現過程
html結構
<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/原生JS實作旋轉木馬式圖片輪播插件" alt="原生JS實作旋轉木馬式圖片輪播插件" ></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/2.jpg" alt="原生JS實作旋轉木馬式圖片輪播插件" ></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/3.jpg" alt="原生JS實作旋轉木馬式圖片輪播插件" ></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/4.jpg" alt="原生JS實作旋轉木馬式圖片輪播插件" ></a> </li> <li class="carrousel-item"> <a href="#"><img src="img/5.jpg" alt="原生JS實作旋轉木馬式圖片輪播插件" ></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' //圖片對齊方式,有topmiddlebottom三種方式,預設為middle
②封裝物件
因為一個網站可能有多個地方都會用到同一個輪播插件,所以封裝很關鍵。定義了這個物件之後,如果給物件定義一個初始化方法是可以建立多個物件的,只需要把所有類別相同的dom傳進去就可以了。所以,我的初始化方法如下:
Carousel.init=function(carrousels){ var _this=this; //将nodeList转换为数组 var cals= toArray(carrousels); <br> /*因为原生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);//越往右边透明度越小<br> //这里的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后等于传入的值的时候清楚计时器即可。具体可以看这里。
好啦,关键的地方都差不多啦,如果明白这些过程应该就很容易了!
四、总结思考
总结:
个人感觉这还是一个比较好理解的插件。如果能结合JQuery来做就相当简单了。但是用原生来写的话,还是有一些不那么流畅的感觉。应该是自定义动画比不上JQuery封装好的动画吧。
还有,这个插件因为图片需要平均分到左右两边,于是对于偶数数量的图片来说,这里用的方法是克隆第一张,然后加到最后,形成一个奇数。
思考:
如果说有bug的话,那就是我定义了一个rotateFlag的标志去判断当前能否旋转,就是预防快速点击的时候跟不上。我在按下的时候把rotateFlag设置为false,然后在动画结束后再把rotateFlag设置为true,但是好像作用并不明显,希望有关大神可以指教一下,大家共同进步。
更多编程相关知识,请访问:编程入门!!