Vue 3 中的 $emit 函数是如何工作的

在 Vue.js 框架中,组件间的通信是一个核心概念。Vue 提供了多种方式来实现父子组件间的通信,其中 $emit 是子组件向父组件发送消息的一种常用手段。在 Vue 3 中,随着 Composition API 的引入,$emit 的使用方式也发生了一些变化,但其核心原理仍然保持不变。

一、Vue 2 中的 $emit

在 Vue 2 中,我们通常在 Vue 实例的 methodscomputed 属性中使用 this.$emit 来触发一个自定义事件,并传递数据给父组件。例如:

复制代码

vue复制代码

|---|------------------------------------------------------|
| | <template> |
| | <button @click="notifyParent">点击通知父组件</button> |
| | </template> |
| | |
| | <script> |
| | export default { |
| | methods: { |
| | notifyParent() { |
| | this.$emit('childToParent', 'Hello from child!'); |
| | } |
| | } |
| | } |
| | </script> |

在这个例子中,当按钮被点击时,notifyParent 方法会被调用,进而通过 this.$emit 触发一个名为 childToParent 的事件,并传递一个字符串 'Hello from child!' 作为参数。

二、Vue 3 中的 $emit

在 Vue 3 中,你仍然可以使用 this.$emit 在 Options API 中触发事件,但如果你选择使用 Composition API,那么就需要从 setup 函数的参数中获取 emit 函数。例如:

复制代码

vue复制代码

|---|---------------------------------------------------|
| | <template> |
| | <button @click="notifyParent">点击通知父组件</button> |
| | </template> |
| | |
| | <script> |
| | import { defineComponent } from 'vue'; |
| | |
| | export default defineComponent({ |
| | setup(props, { emit }) { |
| | const notifyParent = () => { |
| | emit('childToParent', 'Hello from child!'); |
| | }; |
| | |
| | return { notifyParent }; |
| | } |
| | }); |
| | </script> |

在这个例子中,setup 函数接收两个参数:props 和一个包含多个实用函数的上下文对象。我们可以从这个上下文对象中解构出 emit 函数,并在 setup 函数内部使用它来触发事件。

三、$emit 的工作原理

无论是在 Vue 2 还是 Vue 3 中,$emit 的基本工作原理都是相似的。当你在子组件中调用 $emit 函数时,Vue 会查找该组件的父组件,并查看父组件是否监听了你触发的事件。如果父组件监听了该事件,那么它就会调用与该事件相关联的回调函数,并将你传递的数据作为参数传递给这个回调函数。

这个过程是同步的,意味着一旦你调用了 $emit,父组件中的回调函数就会立即被调用。这使得 $emit 成为一种非常有效的组件间通信手段,尤其是当你需要子组件在某种情况下通知父组件时。

四、注意事项

  1. 事件名 :确保你触发的事件名是唯一的,以避免与父组件中其他可能监听的事件发生冲突。通常建议使用 kebab-case(短横线分隔)来命名自定义事件,例如 child-to-parent 而不是 childToParent。但请注意,在模板中监听事件时,你可以使用任何你喜欢的大小写形式,因为 Vue 会自动将它们转换为 kebab-case。然而,在 JavaScript 代码中触发或监听事件时,你需要确保事件名的大小写与模板中的一致。
  2. 数据传递 :你可以通过 $emit 传递任何类型的数据给父组件,包括基本类型、对象、数组等。但是请注意,如果你传递了一个对象或数组,并且在父组件中修改了这个对象或数组,那么子组件中的原始数据也会被修改,因为它们引用的是同一个内存地址。如果你不希望这种情况发生,可以考虑传递一个深拷贝的副本给父组件。
  3. 事件监听与解绑 :在父组件中,你需要使用 v-on@ 指令来监听子组件触发的事件。当子组件被销毁时,Vue 会自动解绑所有与该组件相关联的事件监听器。但是,如果你手动添加了事件监听器(例如通过 addEventListener),那么你需要手动移除它们,以避免内存泄漏和意外行为。
  4. $attrs$listeners 的关系 :在 Vue 2 中,你可以使用 $attrs$listeners 来传递未知的属性和事件给子组件。然而,在 Vue 3 中,这两个属性已经被整合进了 v-bindv-on 的新语法中。这意味着你可以更简洁地在父组件和子组件之间传递属性和事件。但是请注意,如果你显式地定义了一个与从父组件接收的属性或事件同名的属性或事件,那么它将覆盖从父组件接收的值。为了避免这种情况,你可以使用 inheritAttrs: false 选项来阻止自动绑定未知的属性,并手动选择你想要绑定的属性。同时,你也可以使用 v-on="$listeners" 的语法来监听所有从父组件传递下来的事件(尽管在 Vue 3 中这种需求较少见,因为你可以直接监听具体的事件名)。但是请注意,在 Vue 3 中更推荐使用 emits 选项来明确声明子组件可以触发哪些事件,并在父组件中显式地监听这些事件。这可以提高代码的可读性和可维护性,并减少潜在的错误和混淆。同时,使用 emits 选项还可以享受更好的 TypeScript 支持和类型推断功能(如果你在使用 TypeScript 的话)。为了与 Vue 3 的新特性保持一致并充分利用其提供的优势功能(如 Composition API、更灵活的组件间通信方式等),建议在实际开发中优先考虑使用 Vue 3 的新特性和语法规范进行代码编写和组织工作。
相关推荐
码蜂窝编程官方7 分钟前
【含开题报告+文档+PPT+源码】基于SpringBoot+Vue的虎鲸旅游攻略网的设计与实现
java·vue.js·spring boot·后端·spring·旅游
gqkmiss7 分钟前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃12 分钟前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰16 分钟前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter
Viktor_Ye23 分钟前
高效集成易快报与金蝶应付单的方案
java·前端·数据库
hummhumm25 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
乐闻x1 小时前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化
一条晒干的咸魚1 小时前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
花海少爷1 小时前
第十章 JavaScript的应用课后习题
开发语言·javascript·ecmascript
Amd7941 小时前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子