vue组件之轮播图实现

预览地址css

图片的轮播

假设须要轮播三张图片(1,2,3),之前的思路就如图所示,添加两个节点。经过索引(index)的切换实现组件的无缝轮播。html


这种想法的确可行,并且实现出来效果还不错。
缺点在于vue

  • 大量的dom操做。
  • 代码逻辑相对挺复杂,量也更多。
  • 重构或添加新功能会更麻烦

如今的思路

建立两个组件分别为 carouselcarousel-itemgit

结构以下github

<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(){
           //被选中的那个能够显示了,其余的关闭
       }
   }

也就是说 carousel负责数据通讯,而carousel-item只需完成动画过渡效果就好了,这样逻辑就很是清晰了。dom

这里固然就存在动画正向与反向的问题,须要两种方向不一样的切入切出的动画。
carousel须要作一次判断而后在updateChildrens的时候就告诉子组件方向。ide

进入方向的判断

  • 须要一个变量记录上一次的selected数值,假设就为 oldSelectednewSelected
  • 自动轮播是默认正向的(日后播放),到最后一个的时候回到第一个应该也是正向的
  • 圆点(图片索引图标)选取切换,只需判断两次变量的大小就行
  • 方向键切换(箭头图标),和自动轮播同理,方向应时刻和箭头方向一致

解决跳过中间图片的问题

无论轮播图数量多少,这里始终只在两张图里面切换。这样就涉及到一个问题就是会
跳过中间的图片svg

首先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卡片化


须要默认三个同时出现的图片,这意味着须要一个数组。
可是依然不须要改变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就是最好的了。

相关文章
相关标签/搜索