vue3子组件向父组件传递参数
defineEmits
声明事件、emit
触发事件、父组件 @update:count
监听事件,是 Vue3 中 父子组件数据同步 的经典用法,本质是 “子组件主动通知父组件更新数据”,下面从 “定义→触发→接收” 三个环节详细拆解:
一、核心逻辑:为什么需要这套机制?
Vue 规定 子组件不能直接修改父组件的 props(props 是单向数据流),比如子组件不能直接写 props.count += 1
。如果子组件需要修改父组件的变量(比如 “关注用户后,粉丝数 + 1”),就需要通过 “子组件触发事件→父组件监听事件并更新” 的方式实现,这套用法就是为了解决这个问题。
二、分步骤拆解用法
1. 子组件:用 defineEmits
声明 “可触发的事件”
javascript
运行
// 子组件中:声明可以向父组件触发的事件
const emit = defineEmits(['update:count', 'refresh']);
- 作用:告诉 Vue“这个子组件能触发两个事件:
update:count
和refresh
”,相当于给事件 “备案”,避免拼写错误,也让代码更清晰。 - 语法细节:
defineEmits
接收一个数组,数组元素是 “事件名”(建议用update:xxx
格式表示 “更新某个属性”,这是 Vue 推荐的规范)。- 执行后返回一个
emit
函数,子组件通过这个函数触发事件。
2. 子组件:用 emit
触发事件并传递数据
javascript
运行
// 子组件中:比如“关注用户”成功后,触发事件
emit('update:count', props.count + 1);
emit('refresh');
- 作用:子组件在特定时机(如接口调用成功后),通过
emit
函数 “主动通知父组件”,并可携带数据。 - 语法细节:
- 第一个参数:
'update:count'
→ 要触发的 “事件名”(必须和defineEmits
中声明的一致)。 - 第二个参数:
props.count + 1
→ 要传递给父组件的数据(可选,根据需求决定是否传),这里是 “更新后的新数量”。 - 无数据传递时:如
emit('refresh')
,直接触发事件即可,不需要第二个参数。
- 第一个参数:
3. 父组件:用 @事件名
监听事件并更新数据
vue
<!-- 父组件中:调用子组件时,监听 update:count 事件 -->
<UserListPopup ref="fansPopupRef" button-text="粉丝" :count="fansCount" <!-- 父组件传给子组件的初始数量 -->@update:count="fansCount = $event" <!-- 监听事件并更新 -->
/>
- 作用:父组件监听子组件触发的
update:count
事件,接收子组件传递的数据,并更新自己的变量(fansCount
)。 - 语法细节:
@update:count
→@
是v-on:
的简写,表示 “监听子组件的update:count
事件”。$event
→ Vue 内置变量,专门用来接收子组件通过emit
传递的 “第二个参数”(这里就是子组件传来的props.count + 1
)。fansCount = $event
→ 把接收的 “新数量” 赋值给父组件的fansCount
变量,实现 “数据同步”。
三、完整流程示例(结合 “关注用户” 场景)
假设父组件初始 fansCount = 35
,子组件执行 “关注用户” 操作:
- 子组件操作:用户点击 “关注”,接口调用成功后,计算新数量
props.count + 1 = 36
。 - 子组件触发事件:
emit('update:count', 36)
→ 告诉父组件 “需要更新数量,新数量是 36”。 - 父组件监听并更新:
@update:count="fansCount = $event"
→ 父组件接收$event = 36
,把fansCount
从 35 改成 36。 - 页面刷新:父组件
fansCount
更新后,子组件接收的props.count
也会同步变成 36,按钮上的数量({{ count }}
)自动刷新。
四、进阶:用 v-model
简化写法
因为 update:count
是 Vue 推荐的 “更新属性” 事件名,所以可以用 v-model:count
简化父组件的监听代码,效果和 @update:count
完全一致:
vue
<!-- 简化写法:v-model:count 等价于 @update:count="fansCount = $event" -->
<UserListPopup ref="fansPopupRef" button-text="粉丝" v-model:count="fansCount" <!-- 替代 :count 和 @update:count -->
/>
- 原理:
v-model:count="fansCount"
会自动做两件事:- 给子组件传递
count
props(值为fansCount
)。 - 监听子组件的
update:count
事件,把$event
赋值给fansCount
。
- 给子组件传递
五、关键注意点
- 事件名大小写敏感:
update:count
不能写成update:Count
或updateCount
,否则父组件监听不到。 - props 与事件对应:子组件
emit('update:count', 新值)
中的 “新值”,通常基于props.count
计算(保证数据连贯性)。 - 无数据传递的事件:如
emit('refresh')
,父组件监听时直接写@refresh="handleRefresh"
即可(handleRefresh
是父组件的方法)。
update:count
只是事件名,不限制参数数量,传递几个参数完全由业务决定。- 多个参数的写法:子组件
emit
时依次追加,父组件按顺序接收或用对象封装接收。 - 推荐:参数多时用 “对象传递”,避免记顺序,降低维护成本。