vue元件之輪播圖的實現

火貓裸輝耀發表於2019-03-21

預覽地址

圖片的輪播

vue元件之輪播圖的實現

假設需要輪播三張圖片(1,2,3),以前的思路就如圖所示,新增兩個節點。通過索引(index)的切換實現元件的無縫輪播。

vue元件之輪播圖的實現
vue元件之輪播圖的實現

這種想法的確可行,而且實現出來效果還不錯。 缺點在於

  • 大量的dom操作。
  • 程式碼邏輯相對挺複雜,量也更多。
  • 重構或新增新功能會更麻煩

現在的思路

建立兩個元件分別為 carouselcarousel-item

結構如下

<x-carousel :selected.sync="selected">
         <x-carousel-item name="1">
          <div class="box"> 1</div>
         </x-carousel-item>
         <x-carousel-item name="2">
           <div class="box">2</div>
         </x-carousel-item>
         <x-carousel-item name="3">
            <div class="box">3</div>
         </x-carousel-item>
</x-carousel>
複製程式碼

selected即為顯示的內容的name,用sync做一個"雙向繫結"。這樣子父元件就可以通過 updated鉤子和$children來實時通知子元件,從而控制內容的展示。

updated(){
           this.updateChildrens(this.selected)
       }
   methods:{
       updateChildrens(){
           //被選中的那個可以顯示了,其他的關閉
       }
   }
複製程式碼

vue元件之輪播圖的實現

也就是說 carousel負責資料通訊,而carousel-item只需完成動畫過渡效果就行了,這樣邏輯就非常清晰了。

這裡當然就存在動畫正向與反向的問題,需要兩種方向不同的切入切出的動畫。 carousel需要做一次判斷然後在updateChildrens的時候就告訴子元件方向。

進入方向的判斷

  • 需要一個變數記錄上一次的selected數值,假設就為 oldSelectednewSelected
  • 自動輪播是預設正向的(往後播放),到最後一個的時候回到第一個應該也是正向的
  • 圓點(圖片索引圖示)選取切換,只需判斷兩次變數的大小就行
  • 方向鍵切換(箭頭圖示),和自動輪播同理,方向應時刻和箭頭方向一致

解決跳過中間圖片的問題

不管輪播圖數量多少,這裡始終只在兩張圖裡面切換。這樣就涉及到一個問題就是會 跳過中間的圖片

首先carousel-item有一個預設的圖片過渡時間,這裡可以通過計算oldSelectednewSelected之間的差值來確定跳過圖片的數量。當然也有動畫方向的問題。

 clickSelected(newSelected){
               clearInterval(this.timer2)
               if(oldSelected===newSelected)return
               lastSelected = oldSelected
                // .............
               this.‘控制時長的函式’(lastSelected,newSelected)
           },
           
  '控制時長的函式'(lastSelected,newSelected){
               //........
               let newIndex = newSelected 
               let animationDuration = '計時器的間隔時長'
               theIndex = ‘下一個展示的圖片索引’
               //.......
             this.duration = duration  
               this.'carousel元件'.forEach(vm=>vm.duration=duration)
               this.$emit('update:selected',names[theIndex])//通知一下父元件將要展示的下一個圖片的索引
               if(theIndex===newIndex)return
               this.timer2 = setInterval(()=>{
                   if(theIndex===newIndex){
                       this.clearAndSet()
                   }
                   this.$emit('update:selected',names[theIndex])
                   oldIndex>newIndex?theIndex--:theIndex++
               },duration*animationDuration)
  }        
複製程式碼

基本就能完成跳過中間圖片的這樣子的問題了,後面的click改為 hover觸發功能就很簡單了。

Card卡片化

vue元件之輪播圖的實現
需要預設三個同時出現的圖片,這意味著需要一個陣列。 但是依然不需要改變selected的資料型別(還是字串)。這種情況用傳遞陣列只會新增許多不必要的麻煩和降低效能,像是需要做深拷貝,遍歷判斷這類的。 因為這個應該出現的圖片的陣列裡面的index都是連號的。這個判斷只需讓子元件來做就行了。

現在在carousel-item通過計算得到一個陣列

this.cardSelected = [selected-1,selected,selected+1]
if(`最後一張圖`){
    //.....
}else if(`第一張圖`){
    
}
複製程式碼

現在實時顯示的三張圖片的陣列已經有了,我只需要分配好他們的位置(左邊,中間,右邊

'我是決定位置的函式'(){
    let [index,position] = [this.cardSelected.indexOf(Number(this.name)),['left','main','right']]
    return `position-${position[index]}`
}
複製程式碼

簡單的兩行就搞定了。

然後繫結一下

 :class="{......,[我是決定位置的函式]:card}">
複製程式碼

剩下的定位還是動畫什麼的,都可以交給css去完成了。

 &.position-left{
     width: 50%;
     position: absolute;
     top: 0;
     left: -10px;
     transform:scale(0.82);
   }
   &.position-main{
     width: 50%;
     transform: translateX(50%);
     position: relative;
     z-index: 3;
   }
   &.position-right{
     transform: translateX(100%) scale(0.82);
     width: 50%;
     position: absolute;
     top: 0;
     left: 10px;
   }
複製程式碼

最後就是點選兩側圖片會切換

呼叫父元件的方法就ok了

   '呼叫父元件的方法'(){
          let [direction,index] = [this.'我是決定位置的函式'.slice(9,16),this.$parent.selectedIndex]
          if(direction==='main')return
           let move = {left:'back', right:'go'}
           this.$parent.'我是父元件的方法'(index,move[direction])
     }
複製程式碼

尚未完善的細節

其實我認為動畫還是有一點點瑕疵的,後面會在css上修改一下,順便簡單調整樣式和更換動態svg。最後,有待加強的地方希望大佬們指出來交流,要是覺得還行的話,給我的專案點個star就是最好的了。

相關文章