v-model用于两大方面的输入绑定
1)HTML内置表单输入类字段的输入绑定
2)自定义组件的父子组件之间双向值绑定

1. 简化实现

在响应式状态和组件之间,简化双向的“输入”实现

1). 原生表单字段的双向绑定

底层实现原理

<input
  :value="text"
  @input="event => text = event.target.value">

v-model简化实现

<input v-model="text">

2).vue父子组件间的双向绑定

自Vue3.4后,推荐使用defineModel()宏
底层实现原理

<!-- Child.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

<template>
  <input
    :value="props.modelValue"
    @input="emit('update:modelValue', $event.target.value)"
  />
</template>

v-model简化实现

<!-- Child.vue -->
<script setup>
const model = defineModel()

function update() {
  model.value++
}
</script>

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

2. 多个v-model绑定

1).v-model参数

<!-- MyComponent.vue -->
<script setup>
const title = defineModel('title')
</script>

<template>
  <input type="text" v-model="title" />
</template>

2).v-model参数支持多个v-model绑定

// 父组件
<UserName
  v-model:first-name="first"
  v-model:last-name="last"
/>

// 子组件
<script setup>
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
</script>

<template>
  <input type="text" v-model="firstName" />
  <input type="text" v-model="lastName" />
</template>

3. 修饰符特性

1)v-model内置修饰符

https://cn.vuejs.org/guide/essentials/forms.html#modifiers

例如 .trim,.number 和 .lazy

2)自定义修饰符

自定义个修饰符capitalize,对绑定值首字母转大写
a)最终用法

<MyComponent v-model.capitalize="myText" />

b)MyComponent实现

<script setup>
// 解构defineModel
<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1)
    }
    return value
  }
})
</script>

<template>
  <input type="text" v-model="model" />
</template>

3)自定义带v-model参数的修饰符

<UserName
  v-model:first-name.capitalize="first"
  v-model:last-name.uppercase="last"
/>

<script setup>
const [firstName, firstNameModifiers] = defineModel('firstName')
const [lastName, lastNameModifiers] = defineModel('lastName')

console.log(firstNameModifiers) // { capitalize: true }
console.log(lastNameModifiers) // { uppercase: true}
</script>