• 程序化的事件侦听器

    程序化的事件侦听器

    现在,你已经知道了 $emit 的用法,它可以被 v-on 侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法。我们可以:

    • 通过 $on(eventName, eventHandler) 侦听一个事件
    • 通过 $once(eventName, eventHandler) 一次性侦听一个事件
    • 通过 $off(eventName, eventHandler) 停止侦听一个事件你通常不会用到这些,但是当你需要在一个组件实例上手动侦听事件时,它们是派得上用场的。它们也可以用于代码组织工具。例如,你可能经常看到这种集成一个第三方库的模式:
    1. // 一次性将这个日期选择器附加到一个输入框上
    2. // 它会被挂载到 DOM 上。
    3. mounted: function () {
    4. // Pikaday 是一个第三方日期选择器的库
    5. this.picker = new Pikaday({
    6. field: this.$refs.input,
    7. format: 'YYYY-MM-DD'
    8. })
    9. },
    10. // 在组件被销毁之前,
    11. // 也销毁这个日期选择器。
    12. beforeDestroy: function () {
    13. this.picker.destroy()
    14. }

    这里有两个潜在的问题:

    • 它需要在这个组件实例中保存这个 picker,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。
    • 我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。你应该通过一个程序化的侦听器解决这两个问题:
    1. mounted: function () {
    2. var picker = new Pikaday({
    3. field: this.$refs.input,
    4. format: 'YYYY-MM-DD'
    5. })
    6. this.$once('hook:beforeDestroy', function () {
    7. picker.destroy()
    8. })
    9. }

    使用了这个策略,我甚至可以让多个输入框元素同时使用不同的 Pikaday,每个新的实例都程序化地在后期清理它自己:

    1. mounted: function () {
    2. this.attachDatepicker('startDateInput')
    3. this.attachDatepicker('endDateInput')
    4. },
    5. methods: {
    6. attachDatepicker: function (refName) {
    7. var picker = new Pikaday({
    8. field: this.$refs[refName],
    9. format: 'YYYY-MM-DD'
    10. })
    11. this.$once('hook:beforeDestroy', function () {
    12. picker.destroy()
    13. })
    14. }
    15. }

    查阅这个 fiddle 可以了解到完整的代码。注意,即便如此,如果你发现自己不得不在单个组件里做很多建立和清理的工作,最好的方式通常还是创建更多的模块化组件。在这个例子中,我们推荐创建一个可复用的 <input-datepicker> 组件。

    想了解更多程序化侦听器的内容,请查阅实例方法 / 事件相关的 API。

    注意 Vue 的事件系统不同于浏览器的 EventTarget API。尽管它们工作起来是相似的,但是 $emit$on, 和 $off 并不是 dispatchEventaddEventListenerremoveEventListener 的别名。