Vue 单向数据流要求子组件不直接修改 props,而是通过 emit 触发 update 事件通知父组件更新;父组件响应后重渲染,子组件接收新 props 同步视图;v-model 是 :prop + @update:prop 的语法糖,Vue 3.4+ 可用 defineModel 简化。

子组件不能直接修改父组件传来的 props,这是 Vue 单向数据流的基本原则。所谓“通过 emit 同步状态”,本质是子组件用 emit 发出通知,父组件收到后主动更新自己的响应式数据,再通过 props 重新下发——整个过程是“通知→响应→重渲染”,不是“子改父直接生效”。
子组件:不改 props,只发 update 事件
子组件需做三件事:声明接收的 prop、定义要触发的事件、在需要同步时 emit 带新值的 update:xxx 事件。
- 用
defineProps接收父级传入的数据(如modelValue或searchText) - 用
defineEmits明确声明会触发update:modelValue这类事件 - 当用户操作导致本地值变化(比如输入框内容改变),调用
emit('update:modelValue', newValue)
父组件:监听事件并更新自身数据
父组件把数据作为响应式变量(如 ref 或 reactive)持有,并在模板中用 v-model 或显式绑定 + 监听方式响应子组件的通知。
-
<MyInput v-model="inputText" />等价于<MyInput :modelValue="inputText" @update:modelValue="inputText = $event" /> - 如果不用 v-model,就手动写
@update:xxx="val => xxx = val" - 更新后,父组件重新渲染,子组件接收到新 props,视图自动同步
v-model 是语法糖,不是黑箱
v-model 并非特殊机制,它只是对 :prop + @update:prop 的封装。Vue 3 中默认使用 modelValue 和 update:modelValue,但你可以自定义字段名:
- 父组件:
<UserForm v-model:username="name" v-model:email="mail" /> - 子组件:
emit('update:username', 'Tom')或emit('update:email', 't@x.com') - 这样就能在一个组件上管理多个受控状态,逻辑清晰且可追踪
Vue 3.4 新增 defineModel:简化写法
如果你用的是 Vue 3.4+,可以用 defineModel() 一行替代 props 声明和 emit 调用:
-
const model = defineModel('modelValue')—— 自动关联 prop 并封装 emit - 模板中直接写
<input v-model="model.value" />,修改即自动通知父级 - 适合简单表单类组件,大幅减少样板代码,但不适用于需复杂校验或中间处理的场景


















