1️⃣ 监听组件事件

$on() / v-on - 监听事件 $emit() - 把事件沿着作用域链向上派送

父级组件可以像处理 native DOM 事件一样通过 v-on 监听子组件实例的任意事件:
同时子组件可以通过调用内建的 $emit 方法并传入事件名称来触发一个事件:

1️⃣ 事件名

不同于组件和 prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。举个例子,如果触发一个 camelCase 名字的事件:
则监听这个名字的 kebab-case 版本是不会有任何效果的:

  1. <h1 @click="$emit('eventsOne', '向父组件传的参数')">点击</h1>
  2. <component-one @events-one="method"></component-one>

不同于组件和 prop,事件名不会被用作一个 JavaScript 变量名或 property 名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。
因此,我们推荐始终使用 kebab-case 的事件名。

  1. <h1 @click="$emit('events-one', '向父组件传的参数')">点击</h1>
  2. <component-one @events-one="method"></component-one>

1️⃣ 使用事件抛出一个值

  1. <template>
  2. <div id="app">
  3. <component-one @events="method"></component-one>
  4. </div>
  5. </template>
  6. <script>
  7. import ComponentOne from "./components/ComponentOne.vue";
  8. export default {
  9. components: { ComponentOne },
  10. methods: {
  11. method(e) {
  12. console.log("子组件抛出一个事件");
  13. console.log(e);
  14. },
  15. },
  16. };
  17. </script>
  18. <template>
  19. <div class="component-one">
  20. <!-- $emit() 可以写入方法中抛出 -->
  21. <h1 @click="$emit('events', '向父组件传的参数')">点击</h1>
  22. </div>
  23. </template>

image.png

1️⃣ 解绑事件

  1. this.$off('事件名') // 解绑单个事件
  2. this.$off(['事件名', '事件名']) // 解绑多个事件
  3. this.$off() // 解绑所有组件事件

1️⃣ 将原生事件绑定到组件

你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on 的 .native 修饰符:

  1. // 父组件
  2. <template>
  3. <div id="app">
  4. <component-one @focus.native="onFocus"></component-one>
  5. </div>
  6. </template>
  7. <script>
  8. import ComponentOne from "./components/ComponentOne.vue";
  9. export default {
  10. components: { ComponentOne },
  11. methods: {
  12. onFocus() {
  13. console.log("子组件 Focus");
  14. },
  15. },
  16. };
  17. </script>
  1. // 子组件
  2. <template>
  3. <input type="text" />
  4. </template>

image.png
在有的时候这是很有用的,不过在你尝试监听一个类似 的非常特定的元素时,这并不是个好主意。比如上述 组件可能做了如下重构,所以根元素实际上是一个

  1. // 子组件
  2. <template>
  3. <label>
  4. <input type="text" />
  5. </label>
  6. </template>

这时,父级的 .native 监听器将静默失败。它不会产生任何报错,但是 onFocus 处理函数不会如你预期地被调用。
为了解决这个问题,Vue 提供了一个 $listeners

  1. 1. $listeners 包含了父作用域中的 ( 不含 .native 修饰器的 ) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
  1. // 子组件
  2. <template>
  3. <label>
  4. <input type="text" v-on="$listeners" />
  5. </label>
  6. </template>
  7. <script>
  8. export default {
  9. mounted() {
  10. console.log(this.$listeners);
  11. },
  12. };
  13. </script>

有了这个 $listeners property,你就可以配合 v-on=”$listeners” 将所有的事件监听器指向这个组件的某个特定的子元素。

  1. // 父组件
  2. <template>
  3. <div id="app">
  4. <component-one @focus="onFocus" @blur="onBlur"></component-one>
  5. </div>
  6. </template>
  7. <script>
  8. import ComponentOne from "./components/ComponentOne.vue";
  9. export default {
  10. components: { ComponentOne },
  11. methods: {
  12. onFocus() {
  13. console.log("子组件 Focus");
  14. },
  15. onBlur() {
  16. console.log("子组件 Blur");
  17. },
  18. },
  19. };
  20. </script>
  1. // 子组件
  2. <template>
  3. <label>
  4. <input type="text" v-on="$listeners" />
  5. </label>
  6. </template>
  7. <script>
  8. export default {
  9. mounted() {
  10. console.log(this.$listeners);
  11. },
  12. };
  13. </script>

image.png