Vue 3 中的表单输入绑定通过 v-model 指令实现双向数据绑定,可将 input、textarea、select 等表单元素的取值与组件的响应式状态关联。v-model 内置专属修饰符,支持自定义绑定值,是 Vue 开发中处理表单的核心语法,适配所有原生表单元素。
基于 Vue 3 <script setup> 组合式 API,v-model 配合 ref 声明的响应式数据,即可实现表单值与数据的双向同步,覆盖所有原生表单元素场景。
v-model 监听 input 事件,实时同步单行输入框的值与响应式数据。
<script setup>
import { ref } from 'vue'
// 声明响应式数据
const message = ref('')
</script>
<template>
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />
</template>v-model 适用于 textarea 多行文本框,同样监听 input 事件实时同步。 核心规范:textarea 不支持插值表达式,必须使用 v-model 绑定数据。
<script setup>
import { ref } from 'vue'
const message = ref('')
</script>
<template>
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
<!-- 错误写法:插值表达式在 textarea 中无效 -->
<!-- <textarea>{{ message }}</textarea> -->
</template>分为单个复选框(绑定布尔值)和多个复选框(绑定数组)两种场景:
<script setup>
import { ref } from 'vue'
// 单个复选框:布尔值
const checked = ref(false)
// 多个复选框:数组存储选中的 value
const checkedNames = ref([])
</script>
<template>
<!-- 单个复选框 -->
<div>
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
</div>
<!-- 多个复选框 -->
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
</template>一组单选按钮绑定同一个响应式数据,选中后自动赋值为对应 value。
<script setup>
import { ref } from 'vue'
const picked = ref('')
</script>
<template>
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
</template>单选选择器通过 v-model 监听 change 事件同步选中值。 兼容提示:若初始值无匹配选项,select 会渲染为未选中状态,iOS 设备将无法选择第一项,建议添加空值禁用选项。
<script setup>
import { ref } from 'vue'
const selected = ref('')
</script>
<template>
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>通过 v-for 循环渲染动态选项,适配接口返回的选择列表:
<script setup>
import { ref } from 'vue'
const selected = ref('A')
// 动态选项数据
const options = ref([
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' }
])
</script>
<template>
<select v-model="selected">
<option v-for="option in options" :key="option.value" :value="option.value">
{{ option.text }}
</option>
</select>
<div>Selected: {{ selected }}</div>
</template>原生表单元素的 value 默认为字符串 / 布尔值,通过 Vue 专属属性可自定义绑定值,支持动态数据、对象等复杂类型。
使用 Vue 专属属性 true-value / false-value,自定义复选框选中 / 取消的取值,支持动态绑定:
<script setup>
import { ref } from 'vue'
const toggle = ref('no')
// 动态自定义值
const dynamicTrueValue = ref('开启')
const dynamicFalseValue = ref('关闭')
</script>
<template>
<!-- 静态自定义值 -->
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
/>
<label>静态值:{{ toggle }}</label>
<!-- 动态自定义值 -->
<input
type="checkbox"
v-model="toggle"
:true-value="dynamicTrueValue"
:false-value="dynamicFalseValue"
/>
<label>动态值:{{ toggle }}</label>
</template>通过 v-bind 绑定动态变量,选中后自动赋值为变量的值:
<script setup>
import { ref } from 'vue'
const pick = ref('')
const first = ref('选项 1')
const second = ref('选项 2')
</script>
<template>
<input type="radio" v-model="pick" :value="first" />
<label>{{ first }}</label>
<input type="radio" v-model="pick" :value="second" />
<label>{{ second }}</label>
<div>选中值:{{ pick }}</div>
</template>v-model 支持绑定非字符串类型(对象、数字等),直接赋值复杂数据:
<script setup>
import { ref } from 'vue'
const selected = ref(null)
</script>
<template>
<select v-model="selected">
<option :value="{ id: 1, label: '选项 1' }">选项 1</option>
<option :value="{ id: 2, label: '选项 2' }">选项 2</option>
</select>
<div>选中对象:{{ selected }}</div>
</template>v-model 提供 3 个核心修饰符,优化输入行为,适配不同表单场景。
默认 v-model 在 input 事件实时更新数据;添加 .lazy 后,仅在change 事件(失去焦点 / 回车)时同步数据,减少不必要的渲染。
<!-- 失去焦点后更新数据,而非实时更新 -->
<input v-model.lazy="msg" />自动将输入内容转换为数字类型,无法通过 parseFloat() 转换时返回原始值;输入框设置 type="number" 时,该修饰符自动生效。
<script setup>
import { ref } from 'vue'
const age = ref(0)
</script>
<template>
<input type="number" v-model.number="age" />
<p>年龄:{{ age }} | 数据类型:{{ typeof age }}</p>
</template>自动去除用户输入内容首尾的空格,不处理中间空格,规范表单输入格式:
<input v-model.trim="msg" />Vue 3 中 v-model 是语法糖,等价于绑定属性 + 监听事件:
<input v-model="message" />
<!-- 等价于 -->
<input :model-value="message" @update:model-value="message = $event" />select 标签添加 multiple 属性,v-model 绑定数组即可实现多选:
<script setup>
import { ref } from 'vue'
const multiSelected = ref([])
</script>
<template>
<select v-model="multiSelected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<div>多选结果:{{ multiSelected }}</div>
</template>所有表单绑定的数据,必须使用 ref 声明(基础数据类型),才能保证双向绑定生效。
核心用法:v-model 配合 ref 响应式数据,适配所有原生表单元素,<script setup> 是 Vue 3 标准写法;
进阶能力:支持自定义值绑定(对象、动态值)、多选场景,覆盖复杂业务需求;
修饰符:.lazy(延迟更新)、.number(数字转换)、.trim(去空格)是表单开发常用优化手段;
底层逻辑:v-model 是语法糖,本质是属性绑定 + 事件监听。