Vue 3 废弃 .sync 且重构 v-model,父子通信应通过 emit 触发 update:xxx 事件由父组件响应更新;v-model 在 Vue 3 中作为 :prop + @update:prop 的语法糖支持多绑定;禁止直接修改 prop 或用 ref 强制同步;复杂状态推荐抽离至 Pinia 等状态库统一管理。

Vue.js 中父子组件通信,v-model 和 .sync 修饰符曾是简化双向绑定的常用方式,但 Vue 3 已移除 .sync,且 v-model 的行为也全面重构。实际开发中,若需子组件“通知父组件更新某个 prop”,不应依赖已被废弃的机制,而应使用明确、可追踪的事件通信 + 父组件响应式更新。
用 emit 触发更新事件(推荐标准做法)
子组件不直接修改 prop,而是通过 emit 发出语义化事件(如 update:xxx),由父组件监听并更新自身数据。这是 Vue 2 和 Vue 3 都支持、清晰且符合单向数据流原则的方式。
例如子组件需要更新父组件传入的 title:
// 子组件 Child.vue
export default {
props: ['title'],
methods: {
handleChange(newTitle) {
this.$emit('update:title', newTitle) // Vue 2 写法
// Vue 3 写法:this.emit('update:title', newTitle)
}
}
}<!-- 父组件 --><child :title="pageTitle"></child>
这样逻辑明确:子组件只负责“告知变化”,父组件决定是否以及如何响应。
用 v-model 简化语法糖(Vue 3 推荐替代 .sync)
Vue 3 中 v-model 不再仅限于 value,而是可自定义绑定属性名和事件名。它本质就是 :prop + @update:prop 的语法糖,比手动写 @update:xxx 更简洁,且天然支持多 v-model。
子组件声明 model 选项(Vue 2.7+ 或 Vue 3):
export default {
props: ['title'],
model: {
prop: 'title',
event: 'update:title'
},
// Vue 3 setup 中可直接使用 defineModel(v3.4+)
}父组件即可写成:
<child v-model:title="pageTitle"></child>
等价于::title="pageTitle" @update:title="pageTitle = $event" —— 语义更清、代码更短,且完全取代了已废弃的 .sync。
避免直接修改 prop 或使用 ref 强制同步
以下做法应避免:
- 在子组件中直接写
this.title = 'xxx'(Vue 会警告,且不会触发响应) - 用
ref拿到子组件实例后调用其方法更新父状态(破坏封装、难以调试) - 用
provide/inject跨级同步状态(适用场景是深层共享配置或上下文,不是简单父子通信)
这些方式让数据流向模糊,增加维护成本,违背 Vue 的响应式设计初衷。
复杂状态建议抽离为独立响应式对象(Pinia / useState)
当多个 prop 存在联动、校验或副作用时(如表单字段间相互影响),硬靠多个 update:xxx 事件容易混乱。此时更适合将状态提升到父组件统一管理,或使用 Pinia 创建一个表单 store,子组件通过 action 修改 store 状态,父组件自动响应。
例如:
const formStore = useFormStore()
// 子组件中
formStore.updateTitle('new title')父组件直接 {{ formStore.title }} 即可响应 —— 状态单一来源,逻辑集中,便于测试与复用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











