跳到主要内容

v-model 双向绑定原理

面试速答(30 秒版 TL;DR)

  • 本质v-model 是语法糖,拆成 “传值 + 监听更新事件”。
  • 原生表单v-model="x" 约等于 :value="x" @input="x = $event.target.value"(不同控件事件略有差异)。
  • 组件上
    • Vue 2:默认 value + input(可用 model 选项改名)。
    • Vue 3:默认 modelValue + update:modelValue(支持 v-model:xxx 多个模型)。

原生表单(最常见回答)

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

<script setup lang="ts">
import { ref } from 'vue';
const name = ref('');
</script>

等价理解(伪代码):

  • :value="name"
  • @input="name = $event.target.value"

组件上的 v-model(Vue 3)

父组件:

<MyInput v-model="name" />

等价理解:

  • :modelValue="name"
  • @update:modelValue="name = $event"

子组件(核心:接收 prop,发出 update 事件):

<template>
<input :value="modelValue" @input="onInput" />
</template>

<script setup lang="ts">
const props = defineProps<{ modelValue: string }>();
const emit = defineEmits<{ (e: 'update:modelValue', v: string): void }>();

function onInput(e: Event) {
emit('update:modelValue', (e.target as HTMLInputElement).value);
}
</script>

常见追问与坑

  • 不要直接改 props:子组件不能 props.modelValue = ...,要通过 emit('update:modelValue', ...) 通知父组件改。
  • 输入法合成(IME):中文输入过程中会触发 composition 事件,某些场景需要处理 compositionstart/compositionend 避免抖动(多数情况下框架/浏览器已做得够好,但面试可提到意识点)。
  • 修饰符v-model.trim / .number / .lazy 会影响取值与触发时机(见“修饰符”那题)。