程式化的事件偵聽器 點擊打開視頻講解更詳細 現在,你已經知道了 $emit 的用法,它可以被 v-on 偵聽,但是 Vue 實例同時在其事件介面中提供了其它的方法。我們可以: 通過 $on(eventName, eventHandler) 偵聽一個事件 通過 $once(eventName, eve ...
程式化的事件偵聽器
現在,你已經知道了 $emit 的用法,它可以被 v-on 偵聽,但是 Vue 實例同時在其事件介面中提供了其它的方法。我們可以:
- 通過 $on(eventName, eventHandler) 偵聽一個事件
- 通過 $once(eventName, eventHandler) 一次性偵聽一個事件
- 通過 $off(eventName, eventHandler) 停止偵聽一個事件
你通常不會用到這些,但是當你需要在一個組件實例上手動偵聽事件時,它們是派得上用場的。它們也可以用於代碼組織工具。例如,你可能經常看到這種集成一個第三方庫的模式:
// 一次性將這個日期選擇器附加到一個輸入框上
// 它會被掛載到 DOM 上。
mounted: function () {
// Pikaday 是一個第三方日期選擇器的庫
this.picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
},
// 在組件被銷毀之前,
// 也銷毀這個日期選擇器。
beforeDestroy: function () {
this.picker.destroy()
}
這裡有兩個潛在的問題:
- 它需要在這個組件實例中保存這個 picker,如果可以的話最好只有生命周期鉤子可以訪問到它。這並不算嚴重的問題,但是它可以被視為雜物。
- 我們的建立代碼獨立於我們的清理代碼,這使得我們比較難於程式化地清理我們建立的所有東西。
你應該通過一個程式化的偵聽器解決這兩個問題:
mounted: function () {
var picker = new Pikaday({
field: this.$refs.input,
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
使用了這個策略,我甚至可以讓多個輸入框元素同時使用不同的 Pikaday,每個新的實例都程式化地在後期清理它自己:
mounted: function () {
this.attachDatepicker('startDateInput')
this.attachDatepicker('endDateInput')
},
methods: {
attachDatepicker: function (refName) {
var picker = new Pikaday({
field: this.$refs[refName],
format: 'YYYY-MM-DD'
})
this.$once('hook:beforeDestroy', function () {
picker.destroy()
})
}
}
註意,即便如此,如果你發現自己不得不在單個組件里做很多建立和清理的工作,最好的方式通常還是創建更多的模塊化組件。在這個例子中,我們推薦創建一個可復用的
完整案例:
<template>
<div id="app">
<!-- 比如,在頁面掛載時定義計時器,需要在頁面銷毀時清除定時器。這看起來沒什麼問題。但仔細一看 this.timer
唯一的作用只是為了能夠在beforeDestroy 內取到計時器序號,除此之外沒有任何用處。 -->
</div>
</template>
<script>
export default {
name: 'App',
data(){
return {
timer:''
}
},
mounted() {
// this.timer
// 如果可以的話最好只有生命周期鉤子可以訪問到它。這並不算嚴重的問題,但是它可以被視為雜物。
// 我們可以通過 $on 或 $once 監聽頁面生命周期銷毀來解決這個問題
// this.timer = setInterval(() => {
// console.log(Date.now())
// }, 1000)
this.creatInterval('hello') //在mounted中創建多個生命周期函數。
this.creatInterval('world') //即使我們同時創建多個計時器,也不影響效果。因為它們會在頁面銷毀後程式化的自主清除。
},
// beforeDestroy() {
// clearInterval(this.timer)
// },
methods:{
creatInterval(msg) {
let timer = setInterval(() => {
console.log(msg)
}, 1000)
this.$once('hook:beforeDestroy', function() {
clearInterval(timer)
})
}
}
}
</script>
<style scoped>
</style>