VUE3入门很简单(5)---组件通信(自定义事件)

大家好!上回我们聊了 Props ------ 爸爸给娃塞零花钱的单向通道。但现实是:孩子也想说话啊!

比如:"爸,我零花钱花完了!"、"妈,帮我关下灯!"......在 Vue 世界里,这种"喊话"机制就是------自定义事件(Custom Events)

今天,我们就来揭开 defineEmits$emit 的神秘面纱,让你的子组件从此不再"哑巴"!


🗣️ 自定义事件是啥?一句话说清

自定义事件是子组件向父组件传递消息或数据的方式,通过触发事件"通知"父组件:"嘿,我这边有事!"

它和 Props 正好配对:

  • Props:父 → 子(传数据)
  • 自定义事件:子 → 父(传消息/请求)

合体后,就能实现双向通信,比如经典的"表单输入"、"弹窗关闭"、"列表项删除"等场景。


✨ 基本用法:三步教你"喊话"

第一步:子组件定义并触发事件

<script setup> 中,使用 defineEmits 声明你要发射哪些事件(可选但推荐),然后调用它来"喊话"。

html 复制代码
<!-- ChildButton.vue -->
<script setup>
// 声明这个组件会 emit 哪些事件(类型安全 + 文档化)
const emit = defineEmits(['father', 'mother'])

function callFather() {
  // 触发 click 事件,不带参数
  emit('father')
}

function callMother() {
  // 触发 confirm 事件,并传递数据
  emit('mother', { action: 'delete', id: 123 })
}
</script>

<template>
  <button @click="callFather">喊爸爸-给钱</button>
  <button @click="callMother">喊妈妈-关灯</button>
</template>

💡 defineEmits 是宏,无需 import!Vue 3 编译器自动处理。

第二步:父组件监听子组件的事件

在父组件中,像监听原生事件一样,用 @事件名 来接收:

html 复制代码
<!-- Parent.vue -->
<template>
  <ChildButton 
    @father="giveMoney" 
    @mother="turnOffLight" 
  />
</template>

<script setup>
import ChildButton from './ChildButton.vue'

function giveMoney() {
  console.log('给孩子零花钱')
}

function turnOffLight(payload) {
  console.log('收到孩子的请求:', payload) // { action: 'delete', id: 123 }
  // 这里可以调用 API 删除数据、更新状态等
}
</script>

第三步:跑起来!看控制台输出

点击喊爸爸-给钱喊妈妈-关灯按钮,你会看到:

完美!父子沟通无障碍!


⚠️ 注意事项:这些雷区别踩!

1. 不要直接修改父组件数据,而是"请求"

❌ 错误示范(试图绕过事件直接改):

js 复制代码
// 子组件里
props.user.name = '新名字' // 报错!Props 是只读的!

✅ 正确做法:

js 复制代码
// 子组件
emit('update:name', '新名字')

// 父组件
<UserCard @update:name="name = $event" />

2. 事件名用 kebab-case(短横线)更安全

虽然 Vue 支持驼峰(myEvent),但在模板中强烈建议用短横线命名,避免大小写问题:

vue 复制代码
<!-- 推荐 -->
<Child @close-dialog="handleClose" />

<!-- 不推荐(某些环境下可能失效) -->
<Child @closeDialog="handleClose" />

对应地,defineEmits 里写成字符串数组即可:

js 复制代码
defineEmits(['close-dialog'])

3. 事件不是万能的!别滥用

  • 如果多个组件都要响应同一个行为(比如全局通知),考虑用 Pinia
  • 如果只是父子之间简单交互,自定义事件是最轻量、最清晰的选择。

🎯 使用场景:什么时候该"喊话"?

场景 是否适合用自定义事件
子组件按钮点击,父组件执行逻辑 ✅ 经典用法
表单子组件提交数据 ✅ emit('submit', formData)
弹窗/抽屉关闭请求 ✅ emit('close')
列表项被删除 ✅ emit('delete', itemId)
全局状态变更(如用户登录) ❌ 用 Pinia 更合适
兄弟组件通信 ❌ 通过共同父组件中转,或用状态管理

🛠️ 实战示例:一个可关闭的通知卡片

html 复制代码
<!-- NotificationCard.vue -->
<script setup>
const emit = defineEmits(['close'])

function handleClose() {
  emit('close') // 告诉父组件:"我想消失!"
}
</script>

<template>
  <div class="notification">
    <span>🎉 恭喜你学会自定义事件了!</span>
    <button @click="handleClose">×</button>
  </div>
</template>

<style scoped>
.notification {
  display: flex;
  justify-content: space-between;
  padding: 12px;
  background: #e6f7ff;
  border: 1px solid #91d5ff;
}
</style>

父组件使用:

html 复制代码
<!-- App.vue -->
<template>
  <NotificationCard v-if="showNotification" @close="showNotification = false" />
</template>

<script setup>
import { ref } from 'vue'
import NotificationCard from './NotificationCard.vue'

const showNotification = ref(true)
</script>

点击 ×,通知消失!是不是超有成就感?


✅ 总结:自定义事件的黄金法则

  1. 子喊父听 :子组件用 emit 发送,父组件用 @ 监听。
  2. 命名规范 :事件名用短横线(close-dialog),别用驼峰。
  3. 传递数据:可以带任意参数(对象、字符串、数字等)。
  4. 配合 Props:实现完整的父子双向通信。

自定义事件,就像给孩子装了个对讲机------他不能直接改你钱包,但可以大声喊:"爸!再给我五块钱!"

而你,可以选择给,也可以选择拒绝(比如回一句:"自己赚去!" 😏)。

掌握它,你的 Vue 组件就能真正"活"起来!

相关推荐
wuhen_n14 小时前
effect函数的完整实现与追踪:深入Vue3响应式核心
前端·javascript·vue.js
Never_Satisfied14 小时前
在JavaScript / HTML中,img标签loading lazy加载时机详解
开发语言·javascript·html
小飞大王66614 小时前
WebSocket技术与心跳检测
前端·javascript·websocket·网络协议·arcgis
滕青山14 小时前
HTML编码/解码 核心JS实现
前端·javascript·vue.js
RunsenLIu14 小时前
智慧房屋租赁管理系统
前端·javascript·vue.js
程序哥聊面试14 小时前
TypeScript 入门
前端·javascript·typescript
axPpcfNN14 小时前
LCC-LCC无线充电系统:恒流恒压闭环移相控制仿真与优化研究
ecmascript
bai_lan_ya15 小时前
嵌入式linux学习--makefile的使用以及通用解析
开发语言·前端·javascript