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 组件就能真正"活"起来!

相关推荐
●VON2 小时前
React Native for OpenHarmony:解构 TouchableOpacity 的触摸反馈与事件流控制
javascript·学习·react native·react.js·性能优化·openharmony
daols883 小时前
vue 甘特图 vxe-gantt 自定义任务条插槽模板的用法
vue.js·vxe-gantt
小白_ysf3 小时前
Vue 中常见的加密方法(对称、非对称、杂凑算法)
前端·vue.js·算法
2501_944448004 小时前
Flutter for OpenHarmony衣橱管家App实战:支持我们功能实现
android·javascript·flutter
会跑的葫芦怪10 小时前
若依Vue 项目多子路径配置
前端·javascript·vue.js
xiaoqi92211 小时前
React Native鸿蒙跨平台如何进行狗狗领养中心,实现基于唯一标识的事件透传方式是移动端列表开发的通用规范
javascript·react native·react.js·ecmascript·harmonyos
jin12332211 小时前
React Native鸿蒙跨平台剧本杀组队消息与快捷入口组件,包含消息列表展示、快捷入口管理、快捷操作触发和消息详情预览四大核心功能
javascript·react native·react.js·ecmascript·harmonyos
烬头882113 小时前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
pas13613 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js