元件是 Vue 的一個極其重要的概念。在移動端網頁開發時,Toast 元件使用也是非常頻繁的。本文便以 Toast 元件為例,來講解 Vue 元件的部分知識點。
1. 單檔案元件
日常開發時,我們專案資料夾通常都是使用 vue-cli 建立的,以 單檔案元件 的方式來組織程式碼的。按照平日的開發流程,現在先建立一個 Toast.vue 檔案。
我們開始關注實現 Toast 元件的一些要點:
- 該元件有兩個 prop : visible 與 msg。visible 控制顯示與隱藏,msg 是顯示的內容
- 該元件的位置: 相對於螢幕視口來確定位置,position 設定為 fixed,並且把 z-index 值設定大一點。為了讓元素居中顯示,要用到 translate 屬性
- 該元件顯示或者隱藏時新增了動畫: 使用 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 元件。
接下來的調整思路大致如下:
- 檢測是否存在 Toast 元件
- 不存在,建立即可
- 存在的話,重新設定 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 元件的思想 ,而且以後在使用第三方庫的一些元件時,能大致知曉其原理。