尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Vue 中 v-model 的原理和自定义 v-model 怎么用?

Vue 中 v-model 的原理和自定义 v-model 怎么用?
📅 发布时间:2026/7/30 10:31:43

Vue 中 v-model 的原理和自定义 v-model 怎么用?

一句话总结:v-model 本质是「:value+@input」的语法糖,自定义组件用modelValue+update:modelValue即可实现双向绑定,多个 v-model 用具名参数搞定!


正文目录

  1. v-model 到底做了什么?
  2. 5 大高频踩坑场景 & 修复代码
  3. 万能兜底:props + emit + computed 代理
  4. 预防 checklist(不再踩坑)
  5. 一句话总结

一、v-model 到底做了什么?

原生表单元素上用 v-model:

<template> <input v-model="msg" /> </template>

等价于:

<template> <input :value="msg" @input="msg = $event.target.value" /> </template>

核心:v-model = 绑定 value + 监听 input 事件。这不是魔法,是语法糖。

自定义组件上用 v-model(Vue 3):

<!-- 父组件 --> <template> <MyInput v-model="msg" /> </template>

等价于:

<template> <MyInput :modelValue="msg" @update:modelValue="msg = $event" /> </template>

Vue 3 的变化:默认 prop 名从value改为modelValue,事件名从input改为update:modelValue。


二、5 大高频踩坑场景 & 修复代码

① 自定义组件直接修改 modelValue
<!-- ❌ 子组件直接改 prop,触发 Avoid mutating a prop 警告 --> <script setup> const props = defineProps(['modelValue']); const updateText = (e) => { props.modelValue = e.target.value; // ❌ 直接改 prop }; </script> <template> <input :value="modelValue" @input="updateText" /> </template>

修复:用 emit 通知父组件

<!-- ✅ 子组件用 emit 通知父组件修改 --> <script setup> const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); const updateText = (e) => { emit('update:modelValue', e.target.value); // ✅ emit 通知 }; </script> <template> <input :value="modelValue" @input="updateText" /> </template>
② 用 v-model 绑定对象的属性,父组件不更新
<!-- ❌ 子组件修改了对象属性,但父组件的 v-model 没反应 --> <script setup> const props = defineProps(['modelValue']); const handleClick = () => { props.modelValue.name = 'new name'; // ❌ 直接改对象属性,不触发 update }; </script>

修复:emit 一个新对象

<!-- ✅ emit 新对象,触发响应式更新 --> <script setup> const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); const handleClick = () => { emit('update:modelValue', { ...props.modelValue, name: 'new name' }); // ✅ 新对象 }; </script>
③ 一个组件需要多个 v-model
<!-- ❌ 只有一个 v-model,其他属性只能用 prop + emit 手动传 --> <template> <UserForm v-model="user" :name="name" @update:name="name = $event" /> </template>

修复:Vue 3 支持多个具名 v-model

<!-- ✅ 多个 v-model 用具名参数 --> <template> <UserForm v-model:name="name" v-model:age="age" v-model:email="email" /> </template>
<!-- 子组件 --> <script setup> defineProps(['name', 'age', 'email']); defineEmits(['update:name', 'update:age', 'update:email']); </script>
④ v-model 绑定到computed,但没写 setter
<script setup> import { computed } from 'vue'; const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); // ❌ 只读 computed 没有 setter,v-model 写入时报错 const proxy = computed(() => { return props.modelValue.toUpperCase(); }); </script> <template> <input v-model="proxy" /> <!-- ❌ 没有 setter,无法写入 --> </template>

修复:computed 写 get + set

<script setup> import { computed } from 'vue'; const props = defineProps(['modelValue']); const emit = defineEmits(['update:modelValue']); // ✅ computed 带 get/set,代理 v-model const proxy = computed({ get() { return props.modelValue; }, set(val) { emit('update:modelValue', val); } }); </script> <template> <input v-model="proxy" /> <!-- ✅ 读写都通 --> </template>
⑤ 修饰符 .trim / .number / .lazy 在自定义组件上不生效
<!-- ❌ 父组件用了修饰符,但子组件没处理 --> <template> <MyInput v-model.trim="msg" /> <!-- .trim 没有效果 --> </template>

修复:子组件接收 modelModifiers 并处理

<!-- ✅ 子组件处理修饰符 --> <script setup> const props = defineProps({ modelValue: String, modelModifiers: { default: () => ({}) } // ✅ 接收修饰符对象 }); const emit = defineEmits(['update:modelValue']); const handleInput = (e) => { let val = e.target.value; if (props.modelModifiers.trim) { val = val.trim(); // ✅ 手动处理 .trim } emit('update:modelValue', val); }; </script> <template> <input :value="modelValue" @input="handleInput" /> </template>

三、万能兜底:props + emit + computed 代理

场景方案关键点
基本双向绑定defineProps+defineEmitsprop 只读,emit 通知
需要转换值computed get/setget 读 prop,set emit
多个双向绑定具名 v-modelv-model:xxx
对象属性绑定emit 新对象{ ...old, key: newVal }
修饰符处理modelModifiers手动 trim/number/lazy

万能模板:

<!-- 父组件 --> <script setup> import { ref } from 'vue'; import CustomInput from './CustomInput.vue'; const msg = ref(''); const user = ref({ name: '', age: 0 }); </script> <template> <!-- 基本用法 --> <CustomInput v-model.trim="msg" /> <!-- 对象用法 --> <CustomForm v-model="user" /> </template>
<!-- 子组件 CustomInput.vue --> <script setup> import { computed } from 'vue'; const props = defineProps({ modelValue: String, modelModifiers: { default: () => ({}) } }); const emit = defineEmits(['update:modelValue']); // ✅ computed 代理,处理修饰符 const proxy = computed({ get() { return props.modelValue; }, set(val) { if (props.modelModifiers.trim) val = val.trim(); emit('update:modelValue', val); } }); </script> <template> <input v-model="proxy" /> </template>

四、预防 checklist

  • 自定义组件 v-model永远不要直接改 modelValue prop,用 emit
  • 需要转换值时用computed get/set代理,别手动写 input 事件
  • 多个双向绑定用具名 v-model(v-model:xxx),不要叠一堆 prop + emit
  • 绑定对象属性时emit 新对象,不要直接改原对象属性
  • 修饰符在自定义组件上需要手动处理,子组件接收modelModifiers
  • Vue 2 和 Vue 3 的 v-modelprop 名不同(value vs modelValue),迁移注意
  • 表单组件封装时,先写 computed 代理再绑 v-model,一步到位

五、一句话总结

「v-model =:value+@input的语法糖」,自定义组件用modelValue+update:modelValue实现双向绑定,需要转换值就上 computed get/set,多个绑定就用具名 v-model。记住:prop 只读,永远 emit!


最后问候亲爱的朋友们,并邀请你们阅读我的全新著作

📚 《Vue.js 3企业级项目开发实战(微课视频版》

相关新闻

  • MiMo小米 vs DeepSeek V4 编码模型成本全对比|真实账单测算
  • 5个简单步骤:免费解锁Wand专业版的终极指南
  • 2026年亚马逊不侵权报告靠谱服务商盘点及选择攻略避坑FAQ全解析 - 行业观察网

最新新闻

  • 国自然申请冲刺:30天高效优化策略与实战技巧
  • RAGAS测评框架实战
  • EdgeRemover:彻底告别微软Edge浏览器的Windows清理神器
  • 永磁体退磁化与静态工作点:从原理到工程实践的安全设计指南
  • PubMed批量下载工具:告别手动收集,科研效率提升10倍
  • Google Home Speaker 与 Sonos Era 100 大比拼,音质、功能谁更胜一筹?

日新闻

  • 终极TeamSpeak3音乐机器人搭建指南:5分钟实现语音聊天室音频播放
  • 广州海珠区内搬家攻略,平价靠谱搬家服务商推荐,专业打包搬运省心避坑全流程指南 - 厚道搬家
  • 大语言模型入门指南:从零到精通掌握AI核心技术的5大步骤

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号