一、可以使用v-model的标签
你可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。
二、双向绑定
<div id="app">
<input v-model="name" type="text">
{{name}}
</div>
<script>
const vm = new vue({
el: "#app",
data: {
name: "xxx"
}
});
</script>
双向绑定:数据改变时会自动更新视图,视图发生变化时会更新数据。
Vue 则采用的是数据劫持与发布订阅相结合的方式实现双向绑定,数据劫持主要通过 Object.defineProperty 来实现。
我们需要做的就是如何检测到数据的变化然后通知我们去更新视图,如何检测到视图的变化然后去更新数据。检测视图这个比较简单,无非就是我们利用事件的监听即可。
这个内容实际上在数据响应式里有提到:把一个普通 Javascript 对象传给 Vue 实例的 data
选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。
每个组件实例都有相应的watcher实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时(data数据变了),会通知watcher重新计算,从而致使它关联的组件得以更新,这就是数据变化,视图变化。watcher会在getter属性里做出相应的操作。
至于怎么视图变化=>数据变化一会讨论。
上面解释了数据=>视图,解释了v-model的data=>input的值
我们操作被劫持的数据,每次改变数据,被getter知道然后触发get里的某个设置好的函数来更新视图
三、input的单行文本(对应data的字符串)
<input v-model="message" placeholder="edit me" type="text">
<p>Message is:{{ message }}</p>
四、textarea的多行文本(对应data的字符串)
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
五、input的复选框(对应data的数组)
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
new Vue({
el: '#example-3',
data: {
checkedNames: []
}
})
六、input的单选框(对应data的字符串)
<div id="example-4">
<input name='want' type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input name='want' type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
new Vue({
el: '#example-4',
data: {
picked: ''
}
})
单选框最好加一个name表明是同一个name,虽然vue绑定了同一个data暗示了只能选一个,但最后还是写上name
七、select标签的下拉选项(对应data的数组和字符串)
<div id="example-5">
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
new Vue({
el: '...',
data: {
selected: ''
}
})
如果 v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
多选选框在selected加一个multiple即可,一般人不会多选因为多选需要同时按住shift
多选对应数组,单选对应字符串
八、form表单
通常form表单使用一系列input和一个提交按钮实现的,我们通常监听submit事件,阻止提交按钮的默认事件,并且双向绑定input按钮。
九、v-model干了什么
1. vue把下面几个标签改造了一下,所以说input并不是我们熟知的html元素
2. v-model把不同标签对应的属性(等号右边)作为prop(vue固定的)传进去,并且发布对应事件,默认情况下是v-bind:value和v-on:input ="$emit('input', $event.target.value)"的语法糖
v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 元素使用
value
属性和input
事件; - checkbox 和 radio 使用
checked
属性和change
事件; - select 字段将
value
作为 prop 并将change
作为事件。
十、修饰符
.lazy
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转变为使用 change
事件进行同步:
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符:
<input v-model.number="age" type="number">
这通常很有用,因为即使在 type="number"
时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat()
解析,则会返回原始的值。
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符:
<input v-model.trim="msg">
十一、自定义组件
Vue.component('base-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
},
template: `
<input
type="checkbox"
v-bind:checked="checked"
v-on:change="$emit('change', $event.target.checked)"
>
`
})
一个组件上的 v-model
默认会利用名为 value
的 prop 和名为 input
的事件,但是像单选框、复选框等类型的输入控件可能会将 value
attribute 用于不同的目的。model
选项可以用来避免这样的冲突:
现在在这个组件上使用 v-model
的时候:
<base-checkbox v-model="lovingVue"></base-checkbox>
date里的 lovingVue
的值将会传入这个名为 checked
的 prop。同时当 <base-checkbox>
触发一个 change
事件并附带一个新的值的时候,这个 lovingVue
的属性将会被更新。
这就解释了视图=>数据
我们操作视图,触发了v-model发布的事件,事件给父组件新值,从而改变了数据
十二、使用 ant-design-vue
- 创建项目
- 使用组件 $ npm i --save ant-design-vue
- 完整引入/局部引入
import Vue from 'vue';
import Antd from 'ant-design-vue';
import App from './App';
import 'ant-design-vue/dist/antd.css';
Vue.config.productionTip = false;
Vue.use(Antd);
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
});
局部导入组件
import Vue from 'vue';
import { Button, message } from 'ant-design-vue';
import App from './App';
Vue.config.productionTip = false;
/* v1.1.2 */
Vue.component(Button.name, Button);
Vue.component(Button.Group.name, Button.Group);
/* v1.1.3+ 自动注册Button下组件,如Button.Group */
Vue.use(Button);
Vue.prototype.$message = message;
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
});