Vue 3 的 props 是只读的,必须通过 defineModel 或 emit('update:modelValue') 实现双向绑定,直接修改会破坏响应链、导致状态不同步和调试困难。

Vue 3 的 props 是只读的,这是单向数据流原则的强制体现——父组件传入,子组件不得直接修改。但表单编辑场景天然需要“输入即更新”,所以关键不在于绕过限制,而在于用 Vue 接受的方式建立响应式桥梁。核心思路是:**用本地响应式副本承接用户输入,再通过事件通知父组件同步变更**。
用 defineModel 简化双向绑定(推荐 Vue 3.4+)
Vue 3.4 引入 defineModel,让子组件像使用普通 ref 一样操作 v-model 绑定的值,底层自动处理 props 接收和 update:modelValue 派发。
- 子组件中只需一行:
const model = defineModel(),之后可直接读写model.value - 模板中绑定
v-model="model",无需手动声明 props 或 emit - 父组件调用仍为
,完全兼容且代码量减半
手动实现 update:modelValue(兼容所有 Vue 3 版本)
这是最通用、最可控的方式,明确体现单向数据流逻辑。
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
- 子组件定义接收
modelValueprop,并声明update:modelValue事件 - 用
ref或reactive创建本地响应式变量,初始值来自 props - 所有输入框绑定到本地变量,输入时触发
emit('update:modelValue', newValue) - 父组件收到事件后更新自身数据,完成“子改父”的闭环
多字段表单:用 reactive 副本 + watch 同步
当子组件接收一个对象型 props(如 { name: '', email: '' }),适合用 reactive 建立本地副本。
- 用
const localForm = reactive({ ...props.modelValue })初始化 - 用
watch监听 props 变化,及时同步外部更新(防父组件中途改值) - 再用另一个
watch监听localForm变化,触发emit('update:modelValue', { ...localForm }) - 这样既保持响应性,又避免直接修改 props
为什么不能直接改 props?
不是技术上做不到,而是会破坏响应链和可维护性:
- 修改引用类型 props 的属性(如
props.user.name = 'x')虽不报错,但父组件无法感知,状态不同步 - eslint 和 Vue Devtools 会丢失变更溯源,调试困难
- 多个子组件若都直接改同一 props,极易引发竞态和意外覆盖
- 违背设计意图,后续升级或协作时容易埋坑
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!









