子组件应在响应式数据真正更新后立即 emit 通知父组件,而非依赖生命周期钩子;需先更新本地状态再 emit 新值,按语义命名事件如 update:xxx、status-change 等,并确保顺序正确。

子组件内部状态改变时,通过 emit 同步给父级视图,关键在于“状态变化即通知”,而不是等生命周期钩子或用户操作后再补发。父组件不主动轮询,子组件在真实变更发生的那一刻就发出信号。
明确 emit 的触发时机
子组件应在响应式数据真正更新后、视图尚未重绘前(或刚完成重绘后)立即 emit。常见场景包括:
- 响应式变量被赋新值后(如
count.value++之后) - watch 监听到 prop 或内部 ref 变化并完成处理后
- 异步操作(如 API 请求、定时器)返回结果并更新本地状态后
- 表单控件输入、勾选、切换等交互导致 modelValue 改变后
避免在 mounted 或 updated 钩子中无条件 emit —— 这些钩子反映的是渲染阶段,不是业务状态变更点。
使用 defineEmits 声明并调用 emit
Vue 3 <script setup> 中推荐写法:
const emits = defineEmits(['status-change', 'update:modelValue'])
// 状态更新逻辑
const updateStatus = (newVal) => {
status.value = newVal
emits('status-change', newVal) // 立即通知父组件
}父组件监听方式:
<Child @status-change="handleStatusChange" /> <!-- 或配合 v-model --> <Child v-model="localValue" />
区分语义化事件名,提升可维护性
不要只用泛泛的 'change',而应按用途命名:
-
update:xxx:用于响应式同步字段(如update:searchText) -
status-change:通用状态切换(如 loading / idle / error) -
ready:表示子组件已初始化完毕、数据就绪、DOM 可交互 -
error:携带错误对象,供父组件统一提示 -
submit/cancel:表单类组件的明确动作信号
每个事件名对应一个清晰意图,便于父组件做差异化处理。
确保响应式更新与 emit 的顺序正确
常见错误是先 emit、后赋值,导致父组件收到旧值。正确顺序是:
- 更新本地响应式数据(如
ref或reactive属性) - 立即 emit 携带新值(
emits('update:xxx', newValue)) - 若需等待 DOM 更新(如 focus 输入框),可在
nextTick()后 emitready
例如多选框组件同步选中数组:
const toggleItem = (val) => {
const next = modelValue.value.includes(val)
? modelValue.value.filter(v => v !== val)
: [...modelValue.value, val]
modelValue.value = next // 先更新本地状态
emits('update:modelValue', next) // 再通知父组件
}


















