Vue中hook的使用

2021/8/25 Vue

官方文档:程序化的事件侦听器 (opens new window)

$emit方法是传入事件名称来触发一个事件,它可以被v-on侦听,但是Vue实例同时在其事件接口中提供了其它的方法。我们可以:

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

官方文档中的例子是某个组件的创建与销毁,我们更常用的是定时器和添加事件销毁事件

export default {
  name: 'Temp',
  data() {
    return {
      timer: null,
    };
  },
  mounted() {
    this.timer = setInterval(() => {
      // 具体执行内容
    }, 1000);
  },
  beforeDestory() {
    clearInterval(this.timer);
    this.timer = null;
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

这种方法存在的问题是:

  • 它需要在这个组件实例中保存这个timer,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。

  • 创建的定时器代码和销毁定时器的代码没有放在一起,通常很容易忘记去清理这个定时器,不容易维护。这就是文档里说的:

    我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。

    所以我觉得这就是为啥叫程序化的事件侦听器

解决方法:可以用hook来监听beforeDestory生命周期。因为只要监听一次就够了,所以用$once来注册监听。

export default {
  name: 'Temp',
  data() {
    return {};
  },
  mounted() {
    const timer = setInterval(() => {
      // 具体执行代码
      console.log('1');
    }, 1000);
    this.$once('hook:beforeDestory', () => {
      clearInterval(timer);
    });
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

事件的绑定与移除

export default {
  mounted() {
    // 监听窗口发生变化,resize组件
    window.addEventListener('resize', this.resizeFunc);
    // 通过hook监听组件销毁钩子函数,并取消监听事件
    this.$once('hook:beforeDestroy', () => {
      window.removeEventListener('resize', this.resizeFunc);
    });
  },
};
1
2
3
4
5
6
7
8
9
10

文档里面还有一个说明:

WARNING

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

事件监听器还有一个重要的用法,在父组件监听子组件的生命周期方法

场景:父组件如何在子组件的生命周期里做某些处理?例如子组件更新了,但是没有提供change事件,又或者需要在子组件加载更新阶段增加或移除loading效果等

方法一:修改子组件源码,在子组件生命周期中emit父组件

子组件




 



export default {
  name: 'Child',
  mounted() {
    this.$emit('callParent');
  },
};
1
2
3
4
5
6

父组件



 












<template>
  <div>
    <Child @callParent="childCall" />
  </div>
</template>

<script>
export default {
  name: 'Parent',
  methods: {
    childCall() {},
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

方法二:在父组件中使用hook,无需修改子组件



 












<template>
  <div>
    <Child @hook:mounted="childCall" />
  </div>
</template>

<script>
export default {
  name: 'Parent',
  methods: {
    childCall() {},
  },
};
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
最近更新: 2023年03月21日 14:47:21