第5章 Vue表单控件绑定
在Web应用中,我们经常会使用表单向服 务端提交一些数据,而通常也会在表单项中绑定一些如input、change等事件对用户输入的数据进行检验、更新等操作。在Vue.js中,我们可以使用v-model指令同步用户输入的数据到Vue实例data属性中,同时会对radion、checkbox、select等原生表单组件提供一些语法糖使表单操作更加容易。
5.1 基本用法:使用v-model更新表单控件
①text
设置v-model为name,代码如下:
<span>welcome {{name}} join RLW </span>
<input type="text" v-model="name" placeholder="join RLW">
当用户操作文本时,vm.name会自动更新为用户输入的值,同时span的内容也会随之改变。
②checkbox
<input type="checkbox" id="checkbox" v-model="checked"
<label for="checkbox">{{checked}}</label>
当用户勾选了checkbox时,vm.checked=true,否则vm.checked=false,label中的值也会随之改变。
大多数的时候我们使用的都是多个复选框,即一个复选框组。此时,被选中的值将会放在一个数组中。
<input type="checkbox" id="flash" value="flash" v-model="bizLines">
<label for="flash">快车</label>
<input type="checkbox" id="premium" value="premium" v-model="bizLines">
<label for="premium">专车</label>
<input type="checkbox" id="bus" value="bus" v-model="bizLines">
<label for="bus">巴士</label>
<br>
<span>Checked lines:{{ bizLines | json }}</span>
new Vue({
el:'...',
data:{
bizLines:[ ]
}
})
③radio
当单选按钮被选中时,v-model中的变量值会被赋值为对应的value值。
<input type="radio" id="flash" value="flash" v-model="bizLine">
<label for="flash">快车</label>
<br>
<input type="radio" id="bus" value="bus" v-model="bizLine">
<label for="bus">巴士</label>
<br>
<span>Picked:{{ bizLIne }}</span>
④select
因为select控件分为单选和多选,所以v-model在select控件的单选和多选上会有不同的表现。
当被选中的option有value属性时,vm.selected为对应的option的value的值。否则为对应option的text的值。
对于多选select控件,被选中的值会放入一个数组中。
我们也可以通过v-for指令来动态生成option。
5.2 值绑定
在通常情况下,对于radio、checkbox、select组件,通过v-model绑定的值都是字符串,checkbox除外,checkbox可能是布尔值。
<!-- 勾选时`picked`的值是字符串 a -->
<input type="radio" v-model="picked" value="a">
<!-- 勾选时`toggle`的值是布尔值true,否则是布尔值false -->
<input type="checkbox" v-model="toggle">
<!-- 勾选时`selected`的值是字符串 abc -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
有时候我们会有动态绑定Vue.js实例属性的需求,这时可以使用v-bind来实现这个需求。通过v-bind来代替直接使用value属性,我们还可以绑定非字符串的值,如数值、对象、数组等。
①checkbox
<input type="checkbox" v-model="toggle" :true-value="a"
:false-value="b">
勾选checkbox时,vm.toggle == vm.a
未勾选checkbox时,vmtoggle == vm.b
注: :true-value 和 :false-value 只适合同一个checkbox组只有一个checkbox的情况。如果有多个checkbox,请使用:value进行值绑定。
<input type="checkbox" id="flash" :value-"flash" v-model="bizLines">
<label for="flash">{{ flash.name }}</label>
<input type="checkbox" id="premium" :value="premium" v-model="bizLines">
<label for="premium">{{ premium.name }}</label>
<input type="checkbox" id="bus" :value="bus" v-model="bizLines">
<label for="bus">{{ bus.name }}</label>
<br>
<span>Checked bizLines:{{ bizLines | json }}</span>
new Vue({
el:'...',
data:{
flash:{name:'快车'},
premium:{name:'专车'},
bus:{name:'巴士'},
bizLines:[ ]
}
})
②radio
<input type="radio" v-model="pick" :value="a">
勾选radio时,vm.pick === vm.a
③select
<select v-model="selected">
<option :value="{ number:123 }">123</option>
</select>
用户勾选时,vm.selected === {number:123}
5.3 v-model修饰指令
v-model用来在视图与Model之间同步数据,但是有时候我们需要控制同步发生的时机,或者在数据同步到Model之前将数据转换为Number类型。我们可以再v-model指令所在的form控件上添加相应的修饰指令来实现这个需求。
①lazy
在默认情况下,v-model在input事件中同步输入框的值与数据,可以添加一个lazy特性,从而改到在change事件中去同步。
<input v-model="msg" lazy><br/>
{{msg}}
②debounce
设置一个最小的延时,在每次敲击之后延时同步输入框的值到Model中。如果每次更新都要进行高耗操作(列如,在输入提示中AJAX请求)时,它较为有用。
<input v-model="msg" debounce="500">
用户输入完毕500ms后,vm.msg才会被更新。
注:该指令是用来延迟同步用户输入的数据到Model中,并不会延迟用户输入事件执行。所以如果想要获取变化后的数据,我们应该用vm.$watch()来监听msg的变化,而不是在事件中获取最新数据。要想延迟DOM事件的执行,请参阅过滤器章节debounce过滤器。
③number
当传给后端的字段类型必须是数值的时候,我们可以在v-model所在控件上使用number指令,该指令会在用户输入被同步到Model中时将其转换为数值类型,如果转换结果为NaN,则对应的Model值还是用户输入的原始值。
<input v-model="age" number>
5.4 修饰指令原理
①lazy源码解析
所有的表单控件都绑定change,只是在不设置lazy时,默认绑定input。源码定义如下:
<!-- 源码目录: src/directives/public/model/text.js -->
var lazy = this.params.lazy
//...
this.on('change', this.rawListener)
if (!lazy){
this.on('input',this.listener)
}
②debounce源码解析
其实debounce和filter中的debounce原理相似,都是用的同一个函数,核心都是setTimeout,只是debounce没有默认的wait值。
<!-- 源码目录:src/directives/publice/model/text.js -->
③number源码解析
调用util里面的toNumber方法。
<!-- 源码目录:src/directives/public/model/text.js -->
import {
toNumber
} from '../../../util/index'
var number = this.params.number
//...
this.listener = this.rawListener = function () {
if (composing || !self._bound){
return
}
var val = number || isRange ? toNumber(el.value) : el.value
self.set(val)
//...
}
<!-- 源码目录:src/util/lang.js -->
export function toNumber (value) {
if (typeof value !== 'string'){
return value
} else {
var parsed = Number(value)
return isNaN(parsed) ? value : parsed
}
}