用vue寫輪子的一些心得(五)——Slides輪播組件

需求分析

  • 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>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章