08Vue3 表单输入绑定详解

Vue3 提供了 v-model 指令来实现表单元素和数据的双向绑定,使表单处理更加简单高效。

一、基本概念

1.1 v-model 的核心作用

  • 将表单输入元素与 Vue 实例的数据进行双向绑定

  • 自动监听用户的输入事件并更新数据

  • 数据变化时自动更新表单显示

1.2 v-model 与 v-bind + v-on 的关系

在 Vue3 中,v-model 实际上是语法糖:

<!-- v-model 写法 -->
<input v-model="message">

<!-- 等价于 -->
<input 
  :value="message" 
  @input="message = $event.target.value"
>

二、各种表单元素的使用方法

2.1 文本输入框 (Text Input)

<template>
  <div>
    <input v-model="text" placeholder="请输入文本">
    <p>输入的内容:{{ text }}</p>
    
    <!-- 修饰符 -->
    <input v-model.lazy="text" placeholder="懒更新">
    <input v-model.trim="text" placeholder="自动去除首尾空格">
    <input v-model.number="number" placeholder="转为数字" type="number">
  </div>
</template>

<script setup>
import { ref } from 'vue'

const text = ref('')
const number = ref(0)
</script>

2.2 多行文本 (Textarea)

<template>
  <div>
    <textarea v-model="message" rows="3"></textarea>
    <p>消息内容:{{ message }}</p>
    
    <!-- 插值语法在 textarea 中无效 -->
    <!-- 错误写法:<textarea>{{ message }}</textarea> -->
  </div>
</template>

<script setup>
import { ref } from 'vue'

const message = ref('')
</script>

2.3 复选框 (Checkbox)

单个复选框:

<template>
  <div>
    <input type="checkbox" id="agree" v-model="isAgreed">
    <label for="agree">我同意协议</label>
    <p>状态:{{ isAgreed }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const isAgreed = ref(false)
</script>

多个复选框(绑定到数组):

<template>
  <div>
    <input type="checkbox" id="vue" value="Vue" v-model="checkedNames">
    <label for="vue">Vue</label>
    
    <input type="checkbox" id="react" value="React" v-model="checkedNames">
    <label for="react">React</label>
    
    <input type="checkbox" id="angular" value="Angular" v-model="checkedNames">
    <label for="angular">Angular</label>
    
    <p>选中的框架:{{ checkedNames }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const checkedNames = ref([])
</script>

三、修饰符 (Modifiers)

3.1 .lazy - 懒更新

<template>
<input v-model.lazy="message">
<!-- 在 change 事件而非 input 事件后更新 -->
</template>

3.2 .number - 自动转为数字

<template>
  <input v-model.number="age" type="number">
  <!-- 将输入值自动转为数字类型 -->
</template>

3.3 .trim - 自动去除首尾空格

<template>
  <input v-model.trim="username">
  <!-- 自动去除输入内容的首尾空格 -->
</template>

四、进阶用法

4.1 自定义组件的 v-model

Vue3 中,组件可以使用多个 v-model

子组件 ChildComponent.vue:

子组件 ChildComponent.vue:

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

<script setup>
defineProps(['modelValue', 'title'])
defineEmits(['update:modelValue', 'update:title'])
</script>
父组件中使用:

vue
<template>
  <ChildComponent 
    v-model="message"
    v-model:title="pageTitle"
  />
</template>

<script setup>
import { ref } from 'vue'
import ChildComponent from './ChildComponent.vue'

const message = ref('')
const pageTitle = ref('')
</script>

4.2 计算属性与表单绑定

<template>
  <div>
    <input v-model="fullName">
    <p>名字:{{ firstName }}</p>
    <p>姓氏:{{ lastName }}</p>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'

const firstName = ref('张')
const lastName = ref('三')

const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`
  },
  set(newValue) {
    const [first, last] = newValue.split(' ')
    firstName.value = first || ''
    lastName.value = last || ''
  }
})
</script>

4.3 表单验证示例

<template>
  <form @submit.prevent="handleSubmit">
    <div>
      <input 
        v-model.trim="form.email" 
        type="email"
        placeholder="邮箱"
        :class="{ 'error': errors.email }"
      >
      <span v-if="errors.email" class="error-text">{{ errors.email }}</span>
    </div>
    
    <div>
      <input 
        v-model="form.password" 
        type="password"
        placeholder="密码"
        :class="{ 'error': errors.password }"
      >
      <span v-if="errors.password" class="error-text">{{ errors.password }}</span>
    </div>
    
    <button type="submit" :disabled="isSubmitting">提交</button>
  </form>
</template>

<script setup>
import { ref, reactive } from 'vue'

const form = reactive({
  email: '',
  password: ''
})

const errors = reactive({
  email: '',
  password: ''
})

const isSubmitting = ref(false)

const validateForm = () => {
  let isValid = true
  
  // 验证邮箱
  if (!form.email) {
    errors.email = '邮箱不能为空'
    isValid = false
  } else if (!/^\S+@\S+\.\S+$/.test(form.email)) {
    errors.email = '邮箱格式不正确'
    isValid = false
  } else {
    errors.email = ''
  }
  
  // 验证密码
  if (!form.password) {
    errors.password = '密码不能为空'
    isValid = false
  } else if (form.password.length < 6) {
    errors.password = '密码至少6位'
    isValid = false
  } else {
    errors.password = ''
  }
  
  return isValid
}

const handleSubmit = async () => {
  if (!validateForm()) return
  
  isSubmitting.value = true
  try {
    // 提交表单逻辑
    console.log('提交表单:', form)
  } finally {
    isSubmitting.value = false
  }
}
</script>

<style scoped>
.error {
  border-color: red;
}
.error-text {
  color: red;
  font-size: 12px;
}
</style>

五、最佳实践

  1. 使用 .trim 和 .number 修饰符处理常见的数据清洗需求

  2. 复杂的表单验证推荐使用专门的验证库(如 VeeValidate、yup)

  3. 大型表单考虑使用 Composition API 抽离表单逻辑

  4. 性能优化:对不需要实时更新的输入使用 .lazy 修饰符

  5. 可访问性:始终为表单元素添加合适的 label

六、与 Vue2 的区别

  1. 多个 v-model 支持:Vue3 支持在单个组件上使用多个 v-model

  2. 自定义修饰符:Vue3 允许自定义 v-model 修饰符

  3. modelValue 默认属性名:替代 Vue2 的 value

  4. update:modelValue 默认事件名:替代 Vue2 的 input

Vue3 的表单绑定保持了简洁的语法,同时提供了更强大的功能和更好的 TypeScript 支持。

 
posted @ 2026-02-10 15:08  麻辣~香锅  阅读(18)  评论(0)    收藏  举报