Vue2.0 進階元件篇 5 解析 vux(無逢 marquee 元件)

混元霹靂手發表於2017-04-16

作者 : 混元霹靂手-ziksang

我這裡就不帖圖了,marquee就是輪播廣告或公告。。。。。

給vux打打廣告吧,我感覺功能最強大的還是vux ui庫,我帶大家看看這玩意如何實現的,你別看學別人寫元件,還能學到一些你平常用不到的弱知識點,雙擊,666666,沒毛病。

在這裡打個廣告,如果有誰私底下有興趣的,想和我一起打造一套基礎vue的ui元件庫的話,請聯絡我!!!!!!

接下來還是按著我們約定的來

2.程式碼執行vue-cli 2.1版本

3.元件程式碼都在components資料夾裡

4.主程式碼邏輯都在 App.vue資料夾裡

我什麼都不要我只要

在vux中marquee裡分成了兩元件,分別進行slot

1.第一個元件中slot是用來放入每個marquee節點
2.第二個元件中solt是在每個節點放入文案

這有什麼好處呢?

1.第一可以讓程式碼更清楚,在第一個組進行邏輯層編寫和初始化配置
2.第二個元件進行邏輯啟動

這裡的無逢滾動又是如何做到的呢?

1.這裡進行了上滾動和下滾動,分別進行了不同的初始化配置
2.通過cloneChild(true)進行深複製分別辨別direction的位置進行配置

在compoents>marquee>marquee.vue

我們先看看template部分

<template>
  <div class="vux-marquee" :style="{height: height + 'px'}">
    <ul class="vux-marquee-box" ref="box" :style="{transform: `translate3d(0,${currenTranslateY}px,0)`, transition: `transform ${noAnimate ? 0 : duration}ms`}">
      <slot></slot>
    </ul>
  </div>
</template>複製程式碼

解析:
1.首先在class='vux-marquee'dom節點中, 對height進行了樣式配置,這裡的hight起什麼作用,之所以要配置,肯定是要有作用才配置,就是對第一條marquee公告的高度進行復制放入,來進行每條的顯示
2.{transform:translate3d(0,${currenTranslateY}px,0)對每條顯示的位置進行改動 3.transform ${noAnimate ? 0 : duration}ms}對初化第一條和無逢滾動接入的一個時間點我們對動畫時間進行0s設定

再看看script中prop部分

props: {
    interval: {
      type: Number,
      default: 2000
    },
    duration: {
      type: Number,
      default: 300
    },
    direction: {
      type: String,
      default: 'up'
    }
  },複製程式碼

對外暴露的三個屬性
1.interval:每個marquee條目間格多少換一次
2.duration:對動畫時長多少設定
3.direction:對上或下marquee的配置

再看看script中data資料的

data () {
    return {
      currenTranslateY: 0,
      height: '',
      length: 0,
      currentIndex: 0,
      noAnimate: false
    }
  },複製程式碼

1.currenTranslateY :改變的y軸解度存放
2.height:高度存放的值存放
3.length:marquee條目的總長度存放
4.當前每個條目的index下標值存放
5.是否是進行動化的配置值存放

再看看script中methods中三大方法

init () {
      this.destroy()

      if (this.cloneNode) {
        this.$refs.box.removeChild(this.cloneNode)
      }

      this.cloneNode = null
      let firstItem = this.$refs.box.firstElementChild //獲取box節點下的第一個元素
      if (!firstItem) {
        return false 
      }    //如果沒有li元素則退出
      this.length = this.$refs.box.children.length //獲得ul下li節點的長度
      this.height = firstItem.offsetHeight
      if (this.direction === 'up') {
        this.cloneNode = firstItem.cloneNode(true)
        this.$refs.box.appendChild(this.cloneNode)
      } else {
        this.cloneNode = this.$refs.box.lastElementChild.cloneNode(true)
        this.$refs.box.insertBefore(this.cloneNode, firstItem)
      }
    },複製程式碼

這裡是初始化配置方法,我們就挑重要的說
1.this.cloneNode=null進行存放,以但於從新渲染時可以刪除標記
2.firstItem這個變數是拿全marquee盒子中第一個條目dom節點
3.this.length是所有條目的總數
4.this.height是第一個條目的高度,然後滾動檢視就基於第一個條目的高度進行配置
5.在最後的一個this.direction === 'up'這個判斷語句中,可以看出對屬性dircetion來進行初始化配置,這裡同時也是對無逢滾動的操作進行配置,如果是向上滾動,就深度複製第一條目進行最後節點插入,如果是down,就對最後一個條目深度複製插入到第一個條目前

go (toFirst) {
      this.noAnimate = true
      if (toFirst) {
        this.currentIndex = 0
        this.currenTranslateY = 0
      } else {
        this.currentIndex = this.length - 1  //當我們向下marquee的時候,此時最後一個下標為總長度-1
        this.currenTranslateY = -(this.currentIndex + 1) * this.height
        //因為如果向下的話,我們在li的最項部插入了最後一dom此時我們要+1
      }
    }複製程式碼

這個go方法就是中間轉換層
1.在無逢滾動時候對動畫時間設為false則為0,
2.如果tofirst引數為ture時則是向上滾動配置
3.如果tofirst引數為false時則是下面滾洞配置

再看看start方法

start () {
      if (this.direction === 'down') this.go(false) //對初始樣式方向
      this.timer = setInterval(() => {
        if (this.direction === 'up') {
          this.currentIndex += 1
          this.currenTranslateY = -this.currentIndex * this.height
        } else {
          this.currentIndex -= 1
          this.currenTranslateY = -(this.currentIndex + 1) * this.height
        }
        if (this.currentIndex === this.length) {
          setTimeout(() => {
            this.go(true)
          }, this.duration)
        } else if (this.currentIndex === -1) {
          setTimeout(() => {
            this.go(false)
          }, this.duration)
        } else {
          this.noAnimate = false
        }
      }, this.interval + this.duration)
    },複製程式碼

start方法則是啟動方法
if (this.direction === 'down') this.go(false) //對初始樣式方向的第一個條目進行配置,如果是down,則是從最後一條開始,如果是up則是從第一條開始
2.開始定時器開始進行條止滾動如果沒有滾動到深度複製的dom的時候則一直開始動畫時長,如果下標配置到深度複製的dom條目時則傳入false進行go方法過度加入無逢滾動協條!改變translate3d的y方法

marquee.vue完整程式碼

<template>
  <div class="vux-marquee" :style="{height: height + 'px'}">
    <ul class="vux-marquee-box" ref="box" :style="{transform: `translate3d(0,${currenTranslateY}px,0)`, transition: `transform ${noAnimate ? 0 : duration}ms`}">
      <slot></slot>
    </ul>
  </div>
</template>

<script>
export default {
  props: {
    interval: {
      type: Number,
      default: 2000
    },
    duration: {
      type: Number,
      default: 300
    },
    direction: {
      type: String,
      default: 'up'
    }
  },
  beforeDestroy () {
    this.destroy()
  },
  data () {
    return {
      currenTranslateY: 0,
      height: '',
      length: 0,
      currentIndex: 0,
      noAnimate: false
    }
  },
  methods: {
    destroy () {
      this.timer && clearInterval(this.timer)
    },
    init () {
      this.destroy()

      if (this.cloneNode) {
        this.$refs.box.removeChild(this.cloneNode)
      }

      this.cloneNode = null
      let firstItem = this.$refs.box.firstElementChild //獲取box節點下的第一個元素
      if (!firstItem) {
        return false
      }    //如果沒有li元素則退出
      this.length = this.$refs.box.children.length //獲得ul下li節點的長度
      this.height = firstItem.offsetHeight
      if (this.direction === 'up') {
        this.cloneNode = firstItem.cloneNode(true)
        this.$refs.box.appendChild(this.cloneNode)
      } else {
        this.cloneNode = this.$refs.box.lastElementChild.cloneNode(true)
        this.$refs.box.insertBefore(this.cloneNode, firstItem)
      }
    },
    start () {
      if (this.direction === 'down') this.go(false) //對初始樣式方向
      this.timer = setInterval(() => {
        if (this.direction === 'up') {
          this.currentIndex += 1
          this.currenTranslateY = -this.currentIndex * this.height
        } else {
          this.currentIndex -= 1
          this.currenTranslateY = -(this.currentIndex + 1) * this.height
        }
        if (this.currentIndex === this.length) {
          setTimeout(() => {
            this.go(true)
          }, this.duration)
        } else if (this.currentIndex === -1) {
          setTimeout(() => {
            this.go(false)
          }, this.duration)
        } else {
          this.noAnimate = false
        }
      }, this.interval + this.duration)
    },
    go (toFirst) {
      this.noAnimate = true
      if (toFirst) {
        this.currentIndex = 0
        this.currenTranslateY = 0
      } else {
        this.currentIndex = this.length - 1  //當我們向下marquee的時候,此時最後一個下標為總長度-1
        this.currenTranslateY = -(this.currentIndex + 1) * this.height
        //因為如果向下的話,我們在li的最項部插入了最後一dom此時我們要+1
      }
    }
  }
}
</script>
<style lang="less">
.vux-marquee {
  width: 100%;
  overflow:hidden;
}
.vux-marquee-box {
  padding: 0;
  margin: 0;
  width: 100%;
  height: auto;

  li {
    margin: 0;
    width: 100%;
    padding:10px 0;
    box-sizing:border-box;
  }
}
</style>複製程式碼

marquee-item配置

在components>marquee>marquee-item.vue

<template>
  <li>
    <slot></slot>
  </li>
</template>

<script>
export default {
  mounted () {
    this.$nextTick(() => {
      this.$parent.destroy()
      this.$parent.init()
      this.$parent.start()
    })
  }
}
</script>複製程式碼

當每個條目載入dom完畢則開始呼叫,如果是從新渲染,或者切換出去快取的元件則進行時間關畢,再進行Init()初始化,再start()開始滾動

App.vue

<template>
<div>
    <marquee direction='down'>
      <marquee-item class='bb' v-for="i in number" :key = "i">混無霹靂手-ziksang{{i}}</marquee-item>
    </marquee>
</div>
</template>

<script>
import Marquee from './components/marquee/marquee.vue'
import MarqueeItem from './components/marquee/marquee-item.vue'
export default {
    components: {
        Marquee,
        MarqueeItem
    },
    data () {
        return {
            number : 10
        }
    }
}
</script>
<style>
.bb{
    font-size:20px;
}
</style>複製程式碼

然後你就可以啟動了,看看效果如何

渣渣前端開發工程師,喜歡鑽研,熱愛分享和講解教學, 微信 zzx1994428 QQ494755899

支援我繼續創作和感到有收穫的話,請向我打賞點吧

Vue2.0 進階元件篇 5  解析 vux(無逢 marquee 元件)

如果轉載請標註出自@混元霹靂手ziksang

相關文章