> 技术文档 > 【vue-5】Vue 3 中的 v-model:双向数据绑定的全面指南_vue3 修改v-model

【vue-5】Vue 3 中的 v-model:双向数据绑定的全面指南_vue3 修改v-model

在 Vue 开发中,v-model 是实现表单输入和应用状态之间双向绑定的关键指令。Vue 3 对 v-model 进行了重大改进,使其更加灵活和强大。本文将深入探讨 Vue 3 中 v-model 的工作原理、新特性以及最佳实践。

1. v-model 基础

1.1 什么是 v-model

v-model 是 Vue 提供的一个语法糖,它本质上结合了 v-bindv-on

<input v-model=\"message\">

等价于:

<input :value=\"message\" @input=\"message = $event.target.value\">

1.2 基本用法

在表单元素上使用 v-model 非常简单:

<template> <input v-model=\"text\" placeholder=\"请输入\"> <p>你输入的内容是: {{ text }}</p></template><script setup>import { ref } from \'vue\'const text = ref(\'\')</script>

2. Vue 3 中的 v-model 改进

2.1 多个 v-model 绑定

Vue 3 允许在单个组件上使用多个 v-model

<UserName v-model:first-name=\"firstName\" v-model:last-name=\"lastName\"/>

子组件实现:

<script setup>defineProps({ firstName: String, lastName: String})defineEmits([\'update:firstName\', \'update:lastName\'])</script><template> <input :value=\"firstName\" @input=\"$emit(\'update:firstName\', $event.target.value)\" /> <input :value=\"lastName\" @input=\"$emit(\'update:lastName\', $event.target.value)\" /></template>

2.2 v-model 修饰符

Vue 3 支持自定义 v-model 修饰符。例如,创建一个 capitalize 修饰符:

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

子组件处理:

<script setup>const props = defineProps({ modelValue: String, modelModifiers: { default: () => ({}) }})const emit = defineEmits([\'update:modelValue\'])function emitValue(e) { let value = e.target.value if (props.modelModifiers.capitalize) { value = value.charAt(0).toUpperCase() + value.slice(1) } emit(\'update:modelValue\', value)}</script><template> <input :value=\"modelValue\" @input=\"emitValue\" /></template>

3. 不同表单元素的使用

3.1 文本输入

<input v-model=\"text\" type=\"text\">

3.2 多行文本

<textarea v-model=\"message\"></textarea>

3.3 复选框

单个复选框绑定到布尔值:

<input type=\"checkbox\" id=\"checkbox\" v-model=\"checked\"><label for=\"checkbox\">{{ checked }}</label>

多个复选框绑定到数组:

<input type=\"checkbox\" id=\"jack\" value=\"Jack\" v-model=\"checkedNames\"><input type=\"checkbox\" id=\"john\" value=\"John\" v-model=\"checkedNames\"><input type=\"checkbox\" id=\"mike\" value=\"Mike\" v-model=\"checkedNames\">

3.4 单选按钮

<input type=\"radio\" id=\"one\" value=\"One\" v-model=\"picked\"><input type=\"radio\" id=\"two\" value=\"Two\" v-model=\"picked\">

3.5 选择框

单选:

<select v-model=\"selected\"> <option disabled value=\"\">请选择</option> <option>A</option> <option>B</option> <option>C</option></select>

多选(绑定到数组):

<select v-model=\"selected\" multiple> <option>A</option> <option>B</option> <option>C</option></select>

4. v-model 修饰符

Vue 提供了一些内置修饰符来修改 v-model 的行为:

4.1 .lazy

input 事件改为 change 事件:

<input v-model.lazy=\"msg\">

4.2 .number

自动将用户输入转为数字:

<input v-model.number=\"age\" type=\"number\">

4.3 .trim

自动去除用户输入的首尾空白:

<input v-model.trim=\"msg\">

5. 在组件中使用 v-model

5.1 基本实现

子组件:

<script setup>defineProps([\'modelValue\'])defineEmits([\'update:modelValue\'])</script><template> <input :value=\"modelValue\" @input=\"$emit(\'update:modelValue\', $event.target.value)\" /></template>

父组件:

<CustomInput v-model=\"searchText\" />

5.2 带参数的 v-model

子组件:

<script setup>defineProps([\'title\'])defineEmits([\'update:title\'])</script><template> <input type=\"text\" :value=\"title\" @input=\"$emit(\'update:title\', $event.target.value)\" /></template>

父组件:

<MyComponent v-model:title=\"bookTitle\" />

6. 高级技巧

6.1 自定义输入组件

创建一个带验证的输入组件:

<script setup>import { computed } from \'vue\'const props = defineProps({ modelValue: String, required: Boolean, minLength: Number})const emit = defineEmits([\'update:modelValue\'])const error = computed(() => { if (props.required && !props.modelValue) { return \'此字段为必填项\' } if (props.minLength && props.modelValue?.length < props.minLength) { return `至少需要 ${props.minLength} 个字符` } return null})function handleInput(e) { emit(\'update:modelValue\', e.target.value)}</script><template> <input :value=\"modelValue\" @input=\"handleInput\" /> <div v-if=\"error\" class=\"error\">{{ error }}</div></template>

使用:

<ValidatedInput v-model=\"username\" :required=\"true\" :minLength=\"5\"/>

6.2 组合式 API 中的 v-model

使用 computed 实现更复杂的逻辑:

<script setup>import { computed } from \'vue\'const props = defineProps([\'modelValue\'])const emit = defineEmits([\'update:modelValue\'])const value = computed({ get() { return props.modelValue }, set(value) { emit(\'update:modelValue\', value) }})</script>

7. 性能考虑

  1. 避免大型表单的深度响应式:对于大型表单,考虑使用浅响应式或手动管理状态
  2. 防抖处理:频繁的输入可以使用防抖优化性能
  3. 虚拟滚动:对于大量选项的选择框,考虑使用虚拟滚动

8. 常见问题解答

Q: v-model 和 sync 修饰符有什么区别?

A: 在 Vue 2 中,.sync 修饰符用于双向绑定,Vue 3 中已统一使用带参数的 v-model

Q: 为什么我的 v-model 在自定义组件上不工作?

A: 确保子组件正确接收 modelValue prop 并发出 update:modelValue 事件。

Q: 如何处理 v-model 的初始值?

A: 确保父组件为 v-model 绑定的数据提供初始值。

9. 总结

Vue 3 的 v-model 提供了更灵活、更强大的双向数据绑定能力。通过理解其工作原理和各种使用场景,开发者可以构建更复杂、更高效的表单交互。关键点包括:

  1. v-model:value@input 的语法糖
  2. Vue 3 支持多个 v-model 绑定
  3. 可以创建自定义修饰符
  4. 在组件中使用需要正确实现 prop 和 emit

掌握这些概念将大大提升你在 Vue 开发中的效率和代码质量。