以 Toast 為例講解 Vue 元件的概念

zy_deng發表於2017-11-10

元件是 Vue 的一個極其重要的概念。在移動端網頁開發時,Toast 元件使用也是非常頻繁的。本文便以 Toast 元件為例,來講解 Vue 元件的部分知識點。

1. 單檔案元件

日常開發時,我們專案資料夾通常都是使用 vue-cli 建立的,以 單檔案元件 的方式來組織程式碼的。按照平日的開發流程,現在先建立一個 Toast.vue 檔案。

我們開始關注實現 Toast 元件的一些要點:

  1. 該元件有兩個 prop : visible 與 msg。visible 控制顯示與隱藏,msg 是顯示的內容
  2. 該元件的位置: 相對於螢幕視口來確定位置,position 設定為 fixed,並且把 z-index 值設定大一點。為了讓元素居中顯示,要用到 translate 屬性
  3. 該元件顯示或者隱藏時新增了動畫: 使用 transition 元件來實現過渡效果

根據上文的分析,現在的程式碼如下。

<template>
  <transition name="toast-bounce">
    <div class="toast" v-show="visible">
      <p class="toast-msg">{{ msg }}</p>
    </div>  
  </transition>
</template>
<script>
    export default {
      name: 'Toast',
      props: {
          visible: {
              type: Boolean,
              required: true
          },
          msg: {
              type: String,
              required: true
          }
      }
    }
</script>
<style lang="scss" scoped>
// 新增過渡效果
  .toast-bounce-enter, .toast-bounce-leave {
    opacity: 0;
  }
  .toast {
    box-sizing: border-box;
    position: fixed;
    max-width: 80%;
    left: 50%;
    top: 50%;
    padding: 20px;
    z-index: 99;
    transition: all .3s ease;
    transform: translate(-50%, -50%);
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    text-align: center;
    .toast-msg {
      text-align: center;
    }
  }
</style>複製程式碼

在需要使用 Toast 元件的頁面,引入該元件,註冊之後就能使用了。

2. 如何手動建立元件

以單檔案元件引入,有幾個不方便的地方。

  • Toast 每次使用都要匯入
  • 父元件的 state 要包含一個 visible 的屬性 (假設我們沒有使用mixin)
  • 設定 父元件的 visible 為 true 之後,用一個定時器再把 visible 設定為 false

類似這樣使用頻率較高的元件,最便捷的方式是通過呼叫一個函式來完成元件的建立掛載以及銷燬。但而在開發專案過程中,我們把精力放在了元件的實現上,忽略了一些這些操作。接下來我們將演示手動如何建立 Toast 元件,附加到 document.body 下,在顯示一段時間後,銷燬元件,再移除該元素。

元件的建立與掛載

Vue 單檔案的 script 標籤僅僅是匯出一個包含元件選項的物件。為了建立元件,先使用 Vue.extend 得到一個構造器,接下來通過 new 進行例項化。這裡的建構函式有一個可選引數,型別是 Object,可以傳入的屬性有 el,propsData等。

import ToastConfig from './Toast.vue'
// 構造器
const ToastConstructor = Vue.extend(ToastConfig)
// 通過 new 建立元件
const instance = new ToastConstructor()複製程式碼

Toast 元件在建立時,兩個 prop: visible, msg 必須要傳入。在 new 例項化時,配置 propsData 引數來設定元件所需的 prop。

const instance = new ToastConstructor({
    propsData: {
        msg: 'msg',
        visible: false   
    }
})複製程式碼

元件建立與掛載是兩個不同的概念,元件建立時,掛載階段還沒開始,DOM 元素中不含該節點。在 掛載 了之後,才會被瀏覽器渲染。
在建立例項時,不但要設定 propsData屬性,還要設定掛載點 el 屬性,並且將元件附在 document.body 之後。

const instance = new ToastConstructor({
    el: document.createElement('div'),
    propsData: {,
        msg: 'msg',
        visible: false   
    }
})
// 元件建立成功之後掛載
document.body.appendChild(instance.$el)複製程式碼

掛載之後,顯示 toast 元件。再開啟一個定時器,在 3s 之後隱藏元件。

Vue.nextTick(() => {
    instance.visible = true
    setTimeout(() => {
      instance.close()
    }, 3000)
})複製程式碼

元件的銷燬

Toast 元件隱藏的動畫結束時,觸發 transitionend 事件。instance.$el 返回元件的根元素,監聽該元素的 transitionend 事件,在回撥函式中 銷燬 元件,同時從DOM樹中移除。

// 在 ToastConstructor 上新增兩個銷燬元件與移除DOM元素的函式
// 隱藏元件
ToastConstructor.prototype.close = function () {
  this.visible = false
  this.$el.addEventListener('transitionend', this.destroyeInstance.bind(this))
}
// 銷燬元件,移除DOM元素
ToastConstructor.prototype.destroyeInstance = function () {
  this.$destroy(true)
  this.$el.removeEventListener('transitionend', this.destroyeInstance)
  this.$el.parentNode.removeChild(this.$el)
}複製程式碼

完整程式碼片段點選 這裡

3. 小的調整

如果在短時間頻繁呼叫 toast 函式,document.body 下面存在多個 toast 元件,後一個會覆蓋前一個。考慮到移動端的特點,我們希望在同一個時間點上,不論 toast 函式呼叫有多頻繁,document.body 只有會有一個 toast 元件。
接下來的調整思路大致如下:

  1. 檢測是否存在 Toast 元件
  2. 不存在,建立即可
  3. 存在的話,重新設定 state 中的 visible 與 msg,移除銷燬元件的定時器,移除對 transitionend 時間的監聽

程式碼需要進行一些的調整。

// 在函式之外,定義兩個變數
// 元件銷燬時,instance 也要置為 null
let instance = null
let timer = null
function toast (msg = '預設資訊') {
  // 判斷 instance 是否存在
  if (instance) {
    instance.visible = true
    instance.msg = msg
    if (timer) {
      clearInterval(timer)
    }
    instance.$el.removeEventListener('transitionend', instance.destroyeInstance)
  } else {
      //... 
  }
  // ...
}複製程式碼

完整程式碼片段點選 這裡

當然我們也可以再更進一步,把 toast 函式註冊為 Vue 外掛,在需要的地方通過 this.$toast 呼叫即可。element-ui 的 message,vux 的 Toast 都支援外掛方式呼叫。

4. 總結

跟一些成熟的 Vue ui 庫,例如:mint-ui 的 Toast 元件相比,現在的 Toast 元件不足之處很多。但通過編寫一個極其簡單的 Toast 元件,瞭解到 Vue 元件的部分概念,知道了到如何手動建立,銷燬元件,如何結合 transition 製作一些簡單的動畫,有助於我們更好的理解 Vue 元件的思想 ,而且以後在使用第三方庫的一些元件時,能大致知曉其原理。

參考資料

相關文章