预览地址css
假设须要轮播三张图片(1,2,3),之前的思路就如图所示,添加两个节点。经过索引(index)的切换实现组件的无缝轮播。html
这种想法的确可行,并且实现出来效果还不错。
缺点在于vue
建立两个组件分别为 carousel
和 carousel-item
git
结构以下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
数值,假设就为 oldSelected
和newSelected
无论轮播图数量多少,这里始终只在两张图里面切换。这样就涉及到一个问题就是会
跳过中间的图片svg
首先carousel-item
有一个默认的图片过渡时间,这里能够经过计算oldSelected
和newSelected
之间的差值来肯定跳过图片的数量。固然也有动画方向的问题。函数
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就是最好的了。