Vue 为
v-model提供了三个常用修饰符,用于处理常见的表单输入场景。这些修饰符能简化代码,提升用户体验。
默认情况下,v-model 在 input 事件中同步输入框的值,即每次按键都会触发更新:
<input v-model="text">
<p>{{ text }}</p>
用户输入 "hello",每次按键都会触发更新:
添加 .lazy 修饰符后,改为在 change 事件后同步,即失去焦点或回车后才更新:
<input v-model.lazy="text">
<p>{{ text }}</p>
用户输入 "hello",只有失去焦点或按回车才会更新。
1. 表单验证
不需要实时验证的场景,避免频繁触发验证:
<form>
<input
v-model.lazy="email"
@change="validateEmail"
placeholder="邮箱"
>
<span v-if="error">{{ error }}</span>
</form>
<script>
new Vue({
data: {
email: '',
error: ''
},
methods: {
validateEmail: function() {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
this.error = re.test(this.email) ? '' : '邮箱格式不正确'
}
}
})
</script>
2. 中文输入法
使用中文输入法时,拼音输入过程中也会触发更新。使用 .lazy 可以等输入完成再更新:
<!-- 拼音输入过程中不会触发更新 -->
<input v-model.lazy="keyword" placeholder="搜索">
3. 性能优化
对于需要频繁计算或请求的场景,减少触发次数:
<!-- 搜索建议:失去焦点后才请求 -->
<input v-model.lazy="keyword" @change="fetchSuggestions">
即使使用 type="number",v-model 返回的仍然是字符串:
<input type="number" v-model="age">
<p>类型:{{ typeof age }}</p>
<!-- 输入 18,显示 "string" -->
添加 .number 修饰符后,自动将输入转换为数字:
<input type="number" v-model.number="age">
<p>类型:{{ typeof age }}</p>
<!-- 输入 18,显示 "number" -->
parseFloat() 解析,返回数字<input v-model.number="value">
<!-- 输入 "123" → 123 (数字) -->
<!-- 输入 "123.45" → 123.45 (数字) -->
<!-- 输入 "abc" → "abc" (字符串) -->
<!-- 输入 "123abc" → 123 (数字,parseFloat 的行为) -->
1. 年龄、数量等数字输入
<input type="number" v-model.number="age" placeholder="年龄">
<input type="number" v-model.number="quantity" placeholder="数量">
2. 避免字符串比较问题
<!-- ❌ 字符串比较 -->
<input type="number" v-model="age">
<p v-if="age >= 18">成年人</p>
<!-- "18" >= 18 → false(字符串和数字比较) -->
<!-- ✅ 数字比较 -->
<input type="number" v-model.number="age">
<p v-if="age >= 18">成年人</p>
<!-- 18 >= 18 → true -->
3. 计算场景
<div>
<input type="number" v-model.number="price" placeholder="单价">
<input type="number" v-model.number="quantity" placeholder="数量">
<p>总价:{{ price * quantity }}</p>
</div>
<!-- 如果不加 .number,会变成字符串拼接 -->
<!-- "10" * "2" = 20 (正确) -->
<!-- 但 "10" + "2" = "102" (错误) -->
空值处理
输入为空时,.number 返回空字符串,而不是 0:
<input v-model.number="value">
<!-- 空输入 → "" (空字符串) -->
<!-- 需要手动处理 -->
如果需要默认为 0,可以使用计算属性:
computed: {
normalizedValue: {
get: function() {
return this.value
},
set: function(val) {
this.value = val === '' ? 0 : val
}
}
}
用户输入时可能不小心在首尾输入空格:
<input v-model="text">
<!-- 输入 " hello " → text = " hello " -->
添加 .trim 修饰符后,自动去除首尾空格:
<input v-model.trim="text">
<!-- 输入 " hello " → text = "hello" -->
1. 用户名、搜索关键词
<input v-model.trim="username" placeholder="用户名">
<input v-model.trim="keyword" placeholder="搜索">
2. 避免空格导致的验证问题
<input v-model.trim="email" placeholder="邮箱">
<!-- 用户不小心输入空格,自动去除 -->
3. 表单提交前处理
<form @submit.prevent="submit">
<input v-model.trim="name" placeholder="姓名">
<input v-model.trim="email" placeholder="邮箱">
<button type="submit">提交</button>
</form>
中间空格保留
.trim 只去除首尾空格,中间的空格会保留:
<input v-model.trim="text">
<!-- 输入 " hello world " → "hello world" -->
修饰符可以组合使用,执行顺序从左到右:
<!-- lazy + trim -->
<input v-model.lazy.trim="text">
<!-- 失去焦点后更新,并去除首尾空格 -->
<!-- number + trim -->
<input v-model.number.trim="price">
<!-- 转换为数字,并去除首尾空格 -->
<!-- lazy + number + trim -->
<input v-model.lazy.number.trim="age">
<!-- 失去焦点后更新,转换为数字,去除首尾空格 -->
<div id="app">
<form @submit.prevent="register">
<div class="form-group">
<label>用户名</label>
<input
v-model.trim="form.username"
placeholder="用户名(自动去除空格)"
>
</div>
<div class="form-group">
<label>邮箱</label>
<input
type="email"
v-model.trim.lazy="form.email"
@change="validateEmail"
placeholder="邮箱"
>
<span v-if="errors.email" class="error">{{ errors.email }}</span>
</div>
<div class="form-group">
<label>年龄</label>
<input
type="number"
v-model.number="form.age"
placeholder="年龄"
>
</div>
<div class="form-group">
<label>手机号</label>
<input
v-model.trim="form.phone"
placeholder="手机号"
>
</div>
<button type="submit">注册</button>
</form>
<pre>{{ form }}</pre>
</div>
<script>
new Vue({
el: '#app',
data: {
form: {
username: '',
email: '',
age: null,
phone: ''
},
errors: {
email: ''
}
},
methods: {
validateEmail: function() {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
this.errors.email = re.test(this.form.email) ? '' : '邮箱格式不正确'
},
register: function() {
console.log('注册数据:', this.form)
// 发送到服务器...
}
}
})
</script>
<div id="app">
<div class="calculator">
<div class="row">
<label>单价</label>
<input
type="number"
v-model.number.trim="price"
placeholder="单价"
>
</div>
<div class="row">
<label>数量</label>
<input
type="number"
v-model.number.trim="quantity"
placeholder="数量"
>
</div>
<div class="row">
<label>折扣</label>
<input
type="number"
v-model.number.trim="discount"
placeholder="折扣(%)"
>
</div>
<div class="result">
<p>小计:¥{{ subtotal.toFixed(2) }}</p>
<p>折扣:-¥{{ discountAmount.toFixed(2) }}</p>
<p class="total">总计:¥{{ total.toFixed(2) }}</p>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
price: 0,
quantity: 1,
discount: 0
},
computed: {
subtotal: function() {
return this.price * this.quantity
},
discountAmount: function() {
return this.subtotal * (this.discount / 100)
},
total: function() {
return this.subtotal - this.discountAmount
}
}
})
</script>
<div id="app">
<div class="search-form">
<input
v-model.lazy.trim="keyword"
@change="search"
placeholder="输入关键词搜索(回车或失焦触发)"
>
<button @click="search">搜索</button>
</div>
<div v-if="loading" class="loading">搜索中...</div>
<div v-if="results.length > 0" class="results">
<div v-for="item in results" :key="item.id" class="result-item">
<h3>{{ item.title }}</h3>
<p>{{ item.description }}</p>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
keyword: '',
loading: false,
results: []
},
methods: {
search: function() {
if (!this.keyword) {
this.results = []
return
}
this.loading = true
// 模拟 API 调用
setTimeout(() => {
this.results = [
{ id: 1, title: this.keyword + ' 结果一', description: '描述...' },
{ id: 2, title: this.keyword + ' 结果二', description: '描述...' },
{ id: 3, title: this.keyword + ' 结果三', description: '描述...' }
]
this.loading = false
}, 500)
}
}
})
</script>
表单修饰符使用场景总结:
| 修饰符 | 作用 | 适用场景 |
|---|---|---|
.lazy | 失去焦点后更新 | 表单验证、中文输入法、性能优化 |
.number | 转换为数字 | 年龄、数量、价格等数字输入 |
.trim | 去除首尾空格 | 用户名、搜索关键词、邮箱 |
合理使用修饰符,能让表单处理更简洁、用户体验更好。记住:
至此,Vue2 的表单绑定内容已经全部讲解完毕。