除了 v-on 和 $emit 外, Vue 实例在其事件接口中还提供了其它的方法。我们可以:

    • 通过 $on(eventName, eventHandler) 侦听一个事件
    • 通过 $once(eventName, eventHandler) 一次性侦听一个事件
    • 通过 $off(eventName, eventHandler) 停止侦听一个事件

    这几个方法一般不会被用到,但是,当需要在一个组件实例上手动侦听事件时,他们是可以派的上用场的。
    例如,有时我们会在组件中集成第三方库:

    1. Vue.component('my-cmp', {
    2. // 一次性将这个日期选择器附加到一个输入框上
    3. // 它会被挂载到 DOM 上。
    4. mounted () {
    5. // Pikaday 是一个第三方日期选择器的库
    6. this.picker = new Pikaday({
    7. field: this.$refs.input,
    8. format: 'YYYY-MM-DD',
    9. })
    10. },
    11. // 在组件被销毁之前,
    12. // 也销毁这个日期选择器。
    13. beforeDestroy () {
    14. this.picked.destroy();
    15. },
    16. template: `
    17. <div>
    18. <input type="text" ref="input" />
    19. <button @click="$destroy()">销毁组件</button>
    20. </div>
    21. `,
    22. })

    使用上面的方法,有两个潜在的问题:

    • 它需要在这个组件实例中保存这个 picker,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。
    • 我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。

    所有,我们可以通过程序化的侦听器解决这两个问题:

    1. Vue.component('my-cmp', {
    2. mounted () {
    3. var picker = new Pikaday({
    4. field: this.$refs.input,
    5. format: 'YYYY-MM-DD',
    6. })
    7. this.$once('hook:beforeDestroy', () => {
    8. picker.destroy();
    9. })
    10. },
    11. template: `
    12. <div>
    13. <input type="text" ref="input" />
    14. <button @click="$destroy()">销毁组件</button>
    15. </div>
    16. `
    17. })

    使用了这个策略,我们还可以让多个输入框元素使用不同的pikaday:

    1. Vue.component('my-cmp', {
    2. mounted () {
    3. this.datePicker('inputA');
    4. this.datePicker('inputB');
    5. },
    6. methods: {
    7. datePicker (refName) {
    8. var picker = new Pikaday({
    9. field: this.$refs[refName],
    10. format: 'YYYY-MM-DD',
    11. })
    12. this.$once('hook:beforeDestroy', () => {
    13. picker.destroy();
    14. })
    15. },
    16. },
    17. template: `
    18. <div>
    19. <input type="text" ref="inputA" />
    20. <input type="text" ref="inputB" />
    21. <button @click="$destroy()">销毁组件</button>
    22. </div>
    23. `
    24. })

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