vue3中的v-model

76 阅读1分钟

深入理解 Vue3 的 v-model

Vue3 对 v-model 做了非常重要的改进。 相较于 Vue2 的单一绑定机制,Vue3 的 v-model 不仅可以在组件中使用,还可以指定多个 props 来实现更灵活的数据双向绑定。


一、基础原理

v-model 是语法糖,本质上是:

  • 一个 props 绑定(数据输入)
  • 一个事件监听(数据输出)

在原生标签上,Vue 会自动解析为 value + input事件 的组合。

<input v-model="data" />

等价于:

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

二、在组件上的 v-model

当我们在组件上使用时:

<Children v-model="data" />

Vue3 会被编译为:

<Children
  :modelValue="data"
  @update:modelValue="data = $event"
/>

这里的两点非常重要:

元素类型$event 的含义
原生 DOM原生事件对象,例如 input 事件的 event
自定义组件子组件 emit() 传出的参数(不是事件对象

所以:

  • <input> 上要写 data = $event.target.value
  • <Children> 上直接写 data = $event

三、子组件中的写法

在子组件中(假设使用 <script setup> 语法):

<script setup lang="ts">
const props = defineProps<{
  modelValue: string
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
}>()

// 例如在子组件内部某个输入事件中:
function changeValue(e: Event) {
  emit('update:modelValue', (e.target as HTMLInputElement).value)
}
</script>

这样父组件绑定的 v-model="data" 就会自动接收子组件 emit 传回来的值,实现双向绑定。


四、命名多个 v-model

Vue3 支持一个组件定义多个 v-model

<Children
  v-model:age="age"
  v-model:name="name"
/>

它会被编译为:

<Children
  :age="age"
  @update:age="age = $event"
  :name="name"
  @update:name="name = $event"
/>

此时子组件中应当定义相应的 props 和 emits:

<script setup lang="ts">
const props = defineProps<{
  age: number
  name: string
}>()

const emit = defineEmits<{
  (e: 'update:age', value: number): void
  (e: 'update:name', value: string): void
}>()
</script>

五、总结

Vue2 写法Vue3 写法差异
value + inputmodelValue + update:modelValue属性名不同
只能一个 v-model可定义多个命名 v-model灵活性提升
$event.target.value$event 即 emit 传值组件事件不再是原生事件对象

小结记忆口诀

v-model = 绑定一个 prop + 监听一个 update:prop 事件。

原生用 target.value,组件用 $event

多个数据双向绑定?就用命名的 v-model:xxx。# v-model 在vue3 中 v-model 相较于 vue2 有了扩展