表单类控件承载了一个网页数据的录入与交互,本章将介绍如何使用指令 v-model 完成表单的数据双向绑定。
基本用法
表单控件在实际业务较为常见,比如单选、多选、下拉选择、输入框等,用它们可以完成数据的录入、校验、提交等。 Vue.js 提供了 v-model 指令,用于在表单类元素上双向绑定数据,例如在输入框上使用时,输入的内容会实时映射到绑定的数据上。例如下面的例子:
<body> <div id="app"> <input type="text" v-model="message" placeholder="请输入..." /> <p>输入的内容是:{{ message }}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }); </script> </body>
在输入框输入的同时,{{ message } }也会实时将内容渲染在视图中,如下图所示。
对于文本域 textarea 也是同样的用法:
<body> <div id="app"> <textarea v-model="text" placeholder="请输入..."></textarea> <p>输入的内容是:{{ text }}</p> </div> <script> var app = new Vue({ el: '#app', data: { text: '' } }); </script> </body>
使用 v-model 后,表单控件显示的值只依赖所绑定的数据,不再关心初始化时的 value 属性,对于在<textarea></textarea> 之间插入的值,也不会生效. 使用 v-model 时,如果是用中文输入法输入中文,一般在没有选定饲组前,也就是在拼音阶段, Vue 是不会更新数据的,当敲下汉字时才会触发更新。 如果希望总是实时更新,可以用 @input 来替代 v-model. 事实上, v-model 也是一个特殊的语法糖,只不过它会在不同的表单上智能处理。例如下面的示例:
<body> <div id="app"> <input type="text" @input="handleInput" placeholder="输入..." /> <p>输入的内容是:{{ message }}</p> </div> <script> var app = new Vue({ el: '#app', data: { message: '' }, methods: { handleInput: function(e){ this.message = e.target.value; } } }); </script> </body>
来看看更多的表单控件。
- 单选按钮:
单选按钮在单独使用时,不需要 v-model,直接使用 v-bind 绑定一个布尔类型的值, 为真时选中, 为否时不选,例如:<body> <div id="app"> <input type="radio" :checked="picked" /> <label>单选按钮</label> </div> <script> var app = new Vue({ el: '#app', data: { picked: true } }); </script> </body>
如果是组合使用来实现互斥选择的效果,就需要 v-model 配合 value 来使用:
<body> <div id="app"> <input type="radio" v-model="picked" value="html" id="html" /> <label for="html">HTML</label> <br /> <input type="radio" v-model="picked" value="js" id="js" /> <label for="js">JavaScript</label> <br /> <input type="radio" v-model="picked" value="css" id="css" /> <label for="css">CSS</label> <br /> <p>选择的项是:{{ picked }}</p> </div> <script> var app = new Vue({ el: '#app', data: { picked: 'js' } }); </script> </body>
数据 picked 的值与单选按钮的 value 值一致时,就会选中该项,所以当前状态下选中的是第二项 JavaScript,如下图所示。
- 复选框:
复选框也分单独使用和组合使用,不过用法稍与单选不同。复选框单独使用时,也是用 v-model 来绑定一个布尔值,例如:<body> <div id="app"> <input type="checkbox" v-model="checked" id="checked" /> <label for="checked">选择状态:{{ checked }}</label> </div> <script> var app = new Vue({ el: '#app', data: { checked: false } }); </script> </body>
在勾选时,数据 checked 的值变为了 true, label 中渲染的内容也会更新。
组合使用时,也是 v-model 与 value 一起,多个勾选框都绑定到同一个数组类型的数据, value 的值在数组当中,就会选中这一项。这一过程也是双向的,在勾选时, value 的值也会自动 push 到这个数组中,示例代码如下:<body> <div id="app"> <input type="checkbox" v-model="checked" value="html" id="html" /> <label for="html">HTML</label> <br /> <input type="checkbox" v-model="checked" value="js" id="js" /> <label for="js">JavaScript</label> <br /> <input type="checkbox" v-model="checked" value="css" id="css" /> <label for="css">CSS</label> <br /> <p>选择的项是:{{ checked }}</p> </div> <script> var app = new Vue({ el: '#app', data: { checked: ['js','css'] } }); </script> </body>
当前状态下的结果如图所示。
- 选择列表:
选择列表就是下拉选择器,也是常见的表单控件,同样也分为单选和多选两种方式。先看一下单选的示例代码:<body> <div id="app"> <select v-model="selected"> <option>html</option> <option value="js">JavaScript</option> <option>css</option> </select> <p>选择的项是:{{ selected }}</p> </div> <script> var app = new Vue({ el: '#app', data: { selected: 'html' } }); </script> </body>
<option>是备选工页,如果含有 value 属性, v-model 就会优先匹配 value 的值: 如果没有, 就会直接匹配<option>的 text,比如选中第二项时, selected 的值是 js, 而不是 JavaScript。
给<selected>添加属性 multiple 就可以多选了, 此时 v-model 绑定的是一个数组, 与复选框用法类似,示例代码如下:<body> <div id="app"> <select v-model="selected" multiple> <option>html</option> <option value="js">JavaScript</option> <option>css</option> </select> <p>选择的项是:{{ selected }}</p> </div> <script> var app = new Vue({ el: '#app', data: { selected: ['html','js'] } }); </script> </body>
在业务中,<option>经常用 v-for 动态输出, value 和 text 也是用 v-bind 来动态输出的, 例如:
<body> <div id="app"> <select v-model="selected"> <option v-for="option in options" :value="option.value">{{ option.text }}</option> </select> <p>选择的项是:{{ selected }}</p> </div> <script> var app = new Vue({ el: '#app', data: { selected: 'html', options: [ { text: 'HTML', value: 'html' }, { text: 'JavaScript', value: 'js' }, { text: 'CSS', value: 'css' } ] } }); </script> </body>
虽然用选择列表<select>控件可以很简单地完成下拉选择的需求,但是在实际业务中反而不常用,因为它的样式依赖平台和浏览器,无法统一, 也不太美观, 功能也受限, 比如不支持搜索,所以常见的解决方案是用 div 模拟一个类似的控件。当完成后面章节中组件的内容后, 可以尝试编写一个下拉选择器的通用组件。
绑定值
上一节介绍的单选按钮、复选框和选择列表在单独使用或单选的模式下, v-model 绑定的值是一个静态字符串或布尔值, 但在业务中,有时需要绑定一个动态的数据, 这时可以用 v-bind 来实现。
- 单选按钮:
<body> <div id="app"> <input type="radio" v-model="picked" :value="value" /> <label>单选按钮</label> <p>{{ picked }}</p> <p>{{ value }}</p> </div> <script> var app = new Vue({ el: '#app', data: { picked: false, value: 123 } }); </script> </body>
在选中时, app.picked === app.value, 值都是 123。
- 复选框:
<body> <div id="app"> <input type="checkbox" v-model="toggle" :true-value="value1" :fales-value="value2"/> <label>复选框</label> <p>{{ toggle }}</p> <p>{{ value1 }}</p> <p>{{ value2 }}</p> </div> <script> var app = new Vue({ el: '#app', data: { toggle: false, value1: 'a', value2: 'b' } }); </script> </body>
勾选时, app.toggle = app.valuel ; 未勾选时, app.toggle === app.value2。
- 选择列表:
<body> <div id="app"> <select v-model="selected"> <option :value="{ number: 123 }">123</option> </select> {{ selected.number }} </div> <script> var app = new Vue({ el: '#app', data: { selected: '' } }); </script> </body>
当选中时, app.selected 是一个 Object,所以 app.selected.number == 123。
修饰符
与事件的修饰符类似, v-model 也有修饰符,用于控制数据同步的时机。
- .lazy:
在输入框中, v-model 默认是在 input 事件中同步输入框的数据(除了提示中介绍的中文输入法情况外),使用修饰符 .lazy 会转变为在 change 事件中同步,示例代码如下:<body> <div id="app"> <input type="text" v-model.lazy="message" /> {{ message }} </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }); </script> </body>
这时, message 并不是实时改变的,而是在失焦或按回车时才更新。
- .number:
使用修饰符.number 可以将输入转换为 Number 类型,否则虽然你输入的是数字,但它的类型其实是 String,比如在数字输入框时会比较有用,示例代码如下:<body> <div id="app"> <input type="number" v-model.nnumber="message" /> {{ typeof message }} </div> <script> var app = new Vue({ el: '#app', data: { message: 123 } }); </script> </body>
- .trim:
修饰符 .trim 可以自动过滤输入的首尾空格,示例代码如下:<body> <div id="app"> <input type="text" v-model.trim="message" /> {{ message }} </div> <script> var app = new Vue({ el: '#app', data: { message: '' } }); </script> </body>
从 Vue. 2.x 开始, v-model 还可以用于自定义组件,满足定制化的需求, 在下一章会详细介绍。