v-model 本质是 props 下传 + emit 上报的约定,子组件接收 modelValue 并触发 update:modelValue 事件;Vue 3.4+ 推荐用 defineModel 简化双向绑定,支持类型标注与多 v-model 解耦。

v-model 不是魔法,而是基于 props 下传 + emit 上报的明确约定。它让父子组件的状态同步变得简洁、可读、符合 Vue 生态习惯,核心在于子组件不改 prop,只通过事件通知父组件更新。
子组件必须接收 modelValue 并响应式触发 update:modelValue
Vue 3 中 v-model 默认绑定的是 modelValue 这个 prop 名和 update:modelValue 这个事件名。子组件不能用其他名字代替,否则父组件的 v-model="xxx" 就无法自动展开为正确的绑定。
- 在
<script setup>中用defineProps({ modelValue: String })显式声明接收 - 用
defineEmits(['update:modelValue'])声明支持的事件 - 模板中绑定输入框的
:value和监听@input或@change,再调用$emit('update:modelValue', newValue)
推荐用 defineModel 简化双向逻辑(Vue 3.4+)
从 Vue 3.4 开始,defineModel() 宏替代了手动声明 prop + emit 的写法,让代码更紧凑、语义更直接。
递归分析 Vue 项目组件依赖,从入口文件生成组件层级图,支持 Vue 2/3,输出组件名、文件路径和属性。适用于分析组件结构、排查依赖或了解项目架构。
- 它自动返回一个可读写的响应式引用,内部已封装好对
modelValueprop 的映射和update:modelValue的触发 - 写法示例:
const model = defineModel(); <input :value="model.value" @input="model.value = $event.target.value" /> - 仍支持类型标注:
const model = defineModel({ type: String, default: '' });
支持多个 v-model:按字段解耦状态管理
一个组件可以同时响应多个独立的 v-model,比如用户名、邮箱、是否启用等,互不影响。
立即学习“前端免费学习笔记(深入)”;
- 父组件写法:
<UserForm v-model:username="name" v-model:email="mail" /> - 子组件需分别声明:
defineProps({ username: String, email: String }) - 触发对应事件:
emit('update:username', 'Alice')或emit('update:email', 'a@b.com') - 也可配合
defineModel('username')单独定义每个字段的双向绑定
别踩坑:props 不可直接修改,也不该用 watch 同步 value
即使你看到子组件里有个 value prop,也不能直接赋值 this.value = 'new',Vue 会警告“Avoid mutating a prop directly”。同样,不要靠 watch 监听父级传来的值再赋给本地 data —— 这属于反模式,既冗余又容易造成状态不一致。
- 正确做法是把
modelValue当作只读输入,所有变更都走update:modelValue通知父组件 - 如果需要中间处理(如格式化、防抖),应在 emit 前做,而不是绕过 v-model 机制自己维护一份副本

















