需求分析
- Slides組件通常包括一下功能:
- 可支持自動播放
- 可設置自動播放時間
- 輪播圖片高寬可自適應
- 支持觸屏滑動輪播
- 可無縫輪播
方法實現
1、定義組件:
在html中定義
t-slides組件定義爲最外層輪播圖包裹器,t-slides-item組件包裹每張輪播圖片,並且每個t-slides-item組件都聲明一個name,用以標識每張圖片。
<t-slides class="wrapper"
:autoPlay="autoPlay"
:selected.sync="selected">
<t-slides-item name="1">
<div class="box">1</div>
</t-slides-item>
<t-slides-item name="2">
<div class="box">2</div>
</t-slides-item>
<t-slides-item name="3">
<div class="box">3</div>
</t-slides-item>
</t-slides>
2、基礎功能邏輯 :
t-slides單文件組件中的template模板聲明相應鼠標、touch事件。並聲明一個solt插槽用以接收t-slides-item組件數據,這些數據在我們做輪播動畫的時候會用到,稍後我們再聊它們。
t-slides-dots類裏面的內容爲左右點擊切換與顯示輪播圖下標圓點相關功能。
<template>
<div @mouseenter="onMouseEnter"
@mouseleave="onMouseLeave"
@touchend="onTouchEnd"
@touchstart="onTouchStart"
class="t-slides">
<div class="t-slides-window" ref="window">
<div class="t-slides-wrapper">
<slot></slot>
</div>
</div>
<div class="t-slides-dots">
<span @click="onClickPrev" data-action="prev">
<t-icon name="left"></t-icon>
</span>
<span v-for="n in childrenLength" :class="{active: selectedIndex === n-1}"
:key="n" :data-index="n-1"
@click="select(n-1)">
{{n}}
</span>
<span @click="onClickNext" data-aciton="next">
<t-icon name="right"></t-icon>
</span>
</div>
</div>
</template>
通過計算屬性找到this.$children名字等於t-sildes-item的組件數量,這樣就等於獲取到了圖片的數量,從而可執行與數量相關的邏輯。
computed: {
items() {
return this.$children.filter(vm=>vm.$options.name === 't-sildes-item')
}
},
3、自動輪播邏輯:
定義一個方法,用setTimeout模擬setInterval並給setTimeout一個id,在頁面生命週期銷燬前或者任何時候關掉它,這樣可減少性能消耗。有了這個方法自動輪播就很簡單了,mounted的時候執行一下。
playAutomatically() {
if (this.timeId) {return}
let run = () => {
let index = this.names.indexOf(this.getSelected())
let newIndex = index + 1
this.select(newIndex) //告訴外界選中的 newIndex
this.timeId = setTimeout(run, this.autoPlayDelay) //this.autoPlayDelay 時間間隔
}
this.timeId = setTimeout(run, this.autoPlayDelay)
},
4、touch模擬滑動邏輯:
定義touch開始事件結束事件,拿到touch數組的第一項(第一個手指),取出XY軸座標。用Math算出開始橫座標與結束橫座標的角度(三角函數最小邊不超過斜邊的2倍),則角度不會大於30°,角度不大於30°,我們就可以理解用戶是在執行滑動操作。
onTouchEnd(e) {
let endTouch = e.changedTouches[0]
let {clientX: x1, clientY: y1} = this.startTouch
let {clientX: x2, clientY: y2} = endTouch
let distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
let deltaY = Math.abs(y2 - y1)
let rate = distance / deltaY
if (rate > 2) {
if (x2 > x1) {
this.select(this.selectedIndex - 1)
} else {
this.select(this.selectedIndex + 1)
}
}
this.$nextTick(()=> {
this.playAutomatically()
})
},
5、t-slides-item組件無縫輪播相關css:
通過animationEnabled變量控制輪播始終保持2種狀態:1、當前狀態 2、離開狀態。
當前狀態執行當前狀態的樣式類,離開狀態執行另一種樣式類。這樣我們只需要定義兩種樣式類即可做出向左向右的任意動效樣式。
6、輪播圖片高寬可自適應:
只需要在當前狀態類.slide-leave-active中定義position: absolute; width:100%; height: 100%;
其中微妙可自行琢磨。
<template v-if="animationEnabled">
<transition name="slide">
<div class="t-slides-item" v-if="visible" :class="{reverse}">
<slot></slot>
</div>
</transition>
</template>
<template v-else>
<div class="t-slides-item" v-if="visible" :class="{reverse}">
<slot></slot>
</div>
</template>
<style lang="scss" scoped>
.slide-leave-active {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.slide-enter-active, .slide-leave-active {
transition: all 0.5s;
}
.slide-enter {
transform: translateX(100%);
}
.slide-enter.reverse {
transform: translateX(-100%);
}
.slide-leave-to {
transform: translateX(-100%);
}
.slide-leave-to.reverse {
transform: translateX(100%);
}
</style>