第 33 题:Vue3 v-model 原理(语法糖 → props + emit → modelValue → update:modelValue)

第 32 题:Vue3 v-model 原理(语法糖 → props + emit → modelValue → update:modelValue)

回答结构:
核心回答 → 双向绑定机制 → 多个 v-model → 自定义组件实现 → 源码解析 → 面试官追问 → 高分总结


🎯 一、核心回答(面试官最关注)

Vue3 中 v-model 本质是:

props + emits 的语法糖

默认使用:

  • prop:modelValue
  • event:update:modelValue

你写:

ini 复制代码
<MyInput v-model="msg" />

Vue 会转换成:

ini 复制代码
<MyInput 
  :modelValue="msg" 
  @update:modelValue="msg = $event" 
/>

也就是说:

  • 父组件通过 modelValue 把值传给子组件
  • 子组件通过 emit("update:modelValue", newValue) 把值传回父组件

🎯 二、v-model 的完整数据流(非常重要)

vbnet 复制代码
父组件数据(msg)
  ↓ 作为 prop 传递
modelValue
  ↓ 子组件修改后 emit
update:modelValue
  ↓
父组件接收 $event → 更新 msg

这就是 Vue3 的单向数据流 + 事件回传。


🎯 三、子组件必须如何写?

标准写法:

xml 复制代码
<script setup>
const props = defineProps({
  modelValue: String
})

const emit = defineEmits(["update:modelValue"])

function update(e) {
  emit("update:modelValue", e.target.value)
}
</script>

<template>
  <input :value="props.modelValue" @input="update" />
</template>

核心:emit 必须叫 update:modelValue


🎯 四、多个 v-model 原理(Vue3 强化的功能)

你可以写:

ini 复制代码
<MyRange v-model:start="start" v-model:end="end" />

Vue 会转成:

ini 复制代码
<MyRange
  :start="start"
  :end="end"
  @update:start="start = $event"
  @update:end="end = $event"
/>

子组件写法:

arduino 复制代码
const props = defineProps(["start", "end"])

const emit = defineEmits(["update:start", "update:end"])

emit("update:start", newStart)
emit("update:end", newEnd)

Vue2 完全不支持多 v-model

这是 Vue3 的重大升级。


🎯 五、v-model 修饰符原理(.trim、.number、自定义修饰符)

例如:

ini 复制代码
<MyInput v-model.trim="msg" />

会编译成:

ini 复制代码
<MyInput
  :modelValue="msg"
  @update:modelValue="msg = $event.trim()"
/>

自定义修饰符:

ini 复制代码
<MyInput v-model.capitalize="msg" />

Vue 会给 props 添加:

yaml 复制代码
modelModifiers: { capitalize: true }

子组件可读取:

ini 复制代码
if (props.modelModifiers.capitalize) {
  value = value.toUpperCase()
}

🎯 六、源码级解析(重点是 compile 阶段)

Vue 在模板编译时会把:

ini 复制代码
v-model="xxx"

转换成:

css 复制代码
{
  props: [
    createObjectProperty("modelValue", xxx)
  ],
  events: [
    createObjectProperty("onUpdate:modelValue", 
        createAssignmentExpression(xxx, $event)
    )
  ]
}

也就是说:

  • 编译阶段完全变成 props + emit
  • 运行时不需要任何特殊处理

🎯 七、面试官追问(附高分回答)


❓1:Vue3 为什么把 v-model 的字段改成 modelValue?

高分回答:

  • 统一所有组件的输入 prop(没有 value/input 混乱)
  • 多 v-model 必须有字段名
  • modelValue 更标准化

Vue2:

  • value
  • input
  • checked
  • change

非常零散。

Vue3 彻底统一。


❓2:为什么 update:modelValue 这么设计?

因为:

  • Vue3 的事件是通过字符串绑定
  • 冒号语法能清晰表示"更新某个 prop"
  • 可以支持多个 v-model

这是经典的可扩展性设计。


❓3:多个 v-model 怎么区分?

靠:

makefile 复制代码
v-model:title
v-model:desc
v-model:start
v-model:end

字段名前缀。

编译后变成:

ruby 复制代码
:modelValue → :title
@update:modelValue → @update:title

❓4:什么时候用 watch 代替 v-model?

回答:

  • 当你需要监听变化但不希望自动更新值
  • 当你希望多个 props 组合成一个值

否则用 v-model 更简洁。


🎯 八、金牌总结(背下来即可)

Vue3 的 v-model 是 modelValue + update:modelValue 的语法糖,

通过 props 单向流动传值,通过 emit 进行反向更新,实现了可控的双向绑定。

支持多个 v-model,自定义修饰符,编译阶段将 v-model 转换为标准化的 props + emit 结构,是 Vue3 数据流设计中的关键部分。

相关推荐
前端一课30 分钟前
第 25 题:说一下 Vue3 的 keep-alive 原理?缓存是怎么做的?
前端·面试
前端一课32 分钟前
第 30 题:Vue3 自定义渲染器(Custom Renderer)原理- 为什么 Vue 能渲染到 DOM / Canvas / WebGL / 三方平台
前端·面试
前端一课32 分钟前
【vue高频面试题】第 23 题:Vue3 自定义指令(directive)完整解析
前端·面试
前端一课33 分钟前
第 28 题:Vue3 的 Diff 算法核心原理(双端 Diff、PatchFlags、Block Tree、静态提升)
前端·面试
前端一课34 分钟前
【vue高频面试题】第 21 题:Vue3 中的 Slot(插槽)— 基础、原理、使用场景、面试必问点
前端·面试
前端一课35 分钟前
第 24 题:Vue3 的组件通信方式(props / emit / v-model / provide-inject / expose / eventBus
前端·面试
前端一课36 分钟前
第 22 题:Teleport 的作用、原理和使用场景
前端·面试
前端一课36 分钟前
第 29 题:Vue3 的 Teleport 原理(跨层级 DOM 挂载技术)
前端·面试
前端一课36 分钟前
第 31 题:Vue3 中 watchEffect 的原理(依赖自动追踪 + 清理机制 + ReactiveEffect 全流程)
前端·面试