v-model 在 vue 3 中本质是 modelvalue prop 与 update:modelvalue 事件的显式契约;vue 3.4+ 推荐使用 definemodel() 简化实现,支持单/多值绑定及修饰符自动处理。

v-model 在 Vue 3 自定义表单组件中不是自动生效的魔法,而是依赖明确的“数据输入 + 变更通知”契约:子组件接收 modelValue prop,并在值变化时触发 update:modelValue 事件。Vue 3.4+ 还提供了更简洁的 defineModel() 宏来省去样板代码。
基础写法:手动声明 prop 和事件
适用于 Vue 3 全版本,逻辑清晰、兼容性强:
- 在
defineProps中声明modelValue,类型建议覆盖常用类型(如 String / Number / Boolean),并设默认值 - 用
defineEmits(['update:modelValue'])声明可触发事件 - 模板中绑定原生元素的
:value,监听@input或@change,再调用emit('update:modelValue', newValue) - 例如封装一个输入框:
<input :value="modelValue">
支持自定义 v-model 名称(如 v-model:title)
当组件需同时绑定多个字段(如标题、内容、状态)时使用:
- 父组件写法:
<myform v-model:title="post.title" v-model:content="post.content"></myform> - 子组件接收对应 prop:
title和content,分别声明defineEmits(['update:title', 'update:content']) - 内部更新时按字段 emit:
emit('update:title', newVal),而非统一用 modelValue
处理修饰符(.lazy、.number、.trim)
v-model 修饰符不会自动生效,需手动识别并响应:
- 声明
modelModifiers: { default: () => ({}) }prop 来接收修饰符对象 - 检查
modelModifiers.lazy→ 改用@change替代@input - 检查
modelModifiers.number→ emit 前转数字:parseFloat($event.target.value) - 检查
modelModifiers.trim→ emit 前调用.trim()
推荐方案:Vue 3.4+ 使用 defineModel
大幅减少重复代码,语义更直接,是当前最佳实践:
- 单值绑定:
const model = defineModel(),模板中直接<input v-model="model"> - 多值绑定:
const title = defineModel('title'),对应父组件v-model:title - 修饰符自动支持:
v-model.number会自动转数字,v-model.capitalize可配合set函数定制逻辑 - 无需手动声明 props/emits,也不用写 emit 调用,底层已封装好协议
不复杂但容易忽略细节,关键是理解 v-model 的本质是 prop + 事件契约,而不是魔法。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










