Vue3 的 v-model 双向绑定,90% 的人都用错了?(附 2026 最新避坑指南)
你的表单数据绑定了却不动?自定义组件 v-model 写了就是不生效?
而用 Vue3 正确的 v-model 写法,一行代码搞定双向绑定,支持多字段同步、自定义事件、TS 完美兼容——再也不用手动写 $emit('input') 或 .sync 修饰符!
如果你受够了:
- 输入框改了值,页面没反应
- 自定义组件传值像“猜谜游戏”
- Vue2 转 Vue3 后
v-model突然失效 - 团队里有人写
:value + @input,有人写v-model,代码风格混乱
那么,这篇 2026 年最新实操指南,就是为你写的——
不用翻文档,所有代码模板直接复制粘贴,今天就能写出零 bug 的双向绑定!
一、先搞懂:Vue3 的 v-model,到底“新”在哪?
很多从 Vue2 过来的开发者,还在用老思维写 v-model,结果频频翻车。
Vue3 对 v-model 做了三大升级:
| 特性 | Vue2 | Vue3 |
|---|---|---|
| 绑定属性 | 固定为 value
|
可自定义(如 title、count) |
| 触发事件 | input |
统一为 update:xxx |
| 多绑定支持 | 不支持 | 一个组件可绑多个 v-model |
| 语法糖 | 需配合 .sync
|
原生支持,无需额外修饰符 |
一句话总结:Vue3 的
v-model= 更灵活 + 更统一 + 更少代码。
二、核心干货:v-model 3 大场景实战(附可运行模板)
场景1:基础表单绑定(覆盖 80% 日常开发)
适用于 <input>、<textarea>、<select>、复选框等。
【实操代码】(直接复制)
<template>
<div class="form-demo">
<!-- 文本输入 -->
<input v-model="username" placeholder="账号" />
<!-- 密码 -->
<input v-model="password" type="password" placeholder="密码" />
<!-- 多行文本 -->
<textarea v-model="bio" placeholder="个人简介"></textarea>
<!-- 复选框(布尔值) -->
<label>
<input type="checkbox" v-model="agree" />
同意用户协议
</label>
<!-- 实时预览 -->
<div class="preview">
账号:{{ username }}<br/>
密码:{{ password }}<br/>
简介:{{ bio }}<br/>
已同意:{{ agree ? '✅' : '❌' }}
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const password = ref('')
const bio = ref('')
const agree = ref(false)
</script>
避坑提醒:
v-model会自动忽略元素上的value、checked属性,不要混用!
场景2:自定义组件 v-model(组件通信必备)
让自定义组件像原生表单一样使用 v-model。
1. 创建组件:MyInput.vue
<template>
<div class="my-input">
<span>自定义:</span>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
placeholder="请输入..."
/>
</div>
</template>
<script setup>
// 必须叫 modelValue!
const props = defineProps(['modelValue'])
// 必须 emit update:modelValue!
const emit = defineEmits(['update:modelValue'])
</script>
2. 父组件使用
<template>
<MyInput v-model="customText" />
<p>输入内容:{{ customText }}</p>
</template>
<script setup>
import { ref } from 'vue'
import MyInput from './MyInput.vue'
const customText = ref('')
</script>
效果:父组件
v-model="customText"→ 子组件modelValue接收 → 输入时触发update:modelValue→ 父组件自动更新!
场景3:多 v-model 绑定(复杂表单神器)
一个组件同时绑定多个双向数据,比如姓名 + 年龄 + 邮箱。
父组件
<template>
<UserForm
v-model:name="user.name"
v-model:age="user.age"
v-model:email="user.email"
/>
<pre>{{ user }}</pre>
</template>
<script setup>
import { reactive } from 'vue'
import UserForm from './UserForm.vue'
const user = reactive({
name: '',
age: 0,
email: ''
})
</script>
子组件:UserForm.vue
<template>
<div>
<input v-model="nameProxy" placeholder="姓名" />
<input v-model.number="ageProxy" type="number" placeholder="年龄" />
<input v-model="emailProxy" type="email" placeholder="邮箱" />
</div>
</template>
<script setup>
const props = defineProps(['name', 'age', 'email'])
const emit = defineEmits(['update:name', 'update:age', 'update:email'])
// 使用计算属性代理,让 v-model 在子组件内也能用
import { computed } from 'vue'
const nameProxy = computed({
get: () => props.name,
set: (val) => emit('update:name', val)
})
const ageProxy = computed({
get: () => props.age,
set: (val) => emit('update:age', val)
})
const emailProxy = computed({
get: () => props.email,
set: (val) => emit('update:email', val)
})
</script>
优势:父组件只需写
v-model:xxx,逻辑清晰,维护成本极低!
三、实战避坑:90% 的人都会踩的 3 个致命错误
坑1:绑定非响应式数据
// 错误
let text = '' // 普通变量
// v-model="text" → 修改无效!
// 正确
const text = ref('') // 响应式
坑2:自定义组件命名不规范
// 错误(Vue2 写法)
defineProps(['value'])
defineEmits(['input'])
// 正确(Vue3 标准)
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
坑3:v-model 和 :value 混用
<!-- 错误 -->
<input v-model="msg" :value="defaultValue" />
<!-- 正确 -->
<input v-model="msg" />
<!-- 或初始化时:const msg = ref(defaultValue) -->
四、进阶技巧:用 TS 让 v-model 更安全
// MyInput.vue (TypeScript 版)
<script setup lang="ts">
interface Props {
modelValue: string
}
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
}>()
</script>
类型检查 + 智能提示,杜绝拼写错误!
五、谁在用 Vue3 的 v-model?
-
字节跳动:所有内部表单系统强制使用多
v-model模式 -
腾讯文档:协作编辑组件通过
v-model:content实时同步 -
Nuxt 3 官方模板:表单示例全部采用 Composition API +
v-model -
Vue 官方团队:在 RFC 中明确表示 “
v-model是未来组件通信的核心”
结语:双向绑定,本该如此优雅
Vue3 的 v-model 不是“小改动”,而是对组件通信范式的重新定义。
当你能用 v-model:title、v-model:count 一行搞定复杂交互,你就知道——这波升级,值了。
各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!