基础用法
你可以用 v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定。
它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用
value
property 和input
事件; - checkbox 和 radio 使用
checked
property 和change
事件; - select 字段将
value
作为 prop 并将change
作为事件。
对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现
v-model
不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用input
事件。
input 文本
<template>
<div id="app">
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
<p><button @click="message = 'river'">set message to river</button></p>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: 'hi'
}
},
components: {}
};
</script>
复制代码
点击button
,改内存,页面会自动变化。改页面的东西,内存也会自动变化。这就是双向数据绑定
textarea 多行文本
<template>
<div id="app">
<textarea v-model="message" placeholder="edit me" />
<p>Message is: {{ message }}</p>
<p><button @click="message = 'river'">set message to river</button></p>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: 'hi'
}
},
components: {}
};
</script>
复制代码
在文本区域插值 (
<textarea>{{text}}</textarea>
) 并不会生效,应用v-model
来代替。
checkbox 复选框
单个复选框
<template>
<div id="app">
<label>
<input type="checkbox" v-model="x">
<span>x:{{ x }}</span>
</label>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
x: true
}
},
components: {}
};
</script>
复制代码
单个复选框,绑定到布尔值
多个复选框
<template>
<div id="app">
爱好:{{x}},
<label>
<input type="checkbox" v-model="x" :value="1">
<span>抽烟</span>
</label>
<label>
<input type="checkbox" v-model="x" :value="2">
<span>喝酒</span>
</label>
<label>
<input type="checkbox" v-model="x" :value="3">
<span>烫头</span>
</label>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
x: []
}
},
components: {}
};
</script>
复制代码
多个复选框,绑定到同一个数组
radio 单选按钮
<template>
<div id="app">
你想要:{{x}},
<label>
<input name="want" type="radio" v-model="x" :value="1">
<span>抽烟</span>
</label>
<label>
<input name="want" type="radio" v-model="x" :value="2">
<span>喝酒</span>
</label>
<label>
<input name="want" type="radio" v-model="x" :value="3">
<span>烫头</span>
</label>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
x: []
}
},
components: {}
};
</script>
复制代码
select 选择框
单选时
<template>
<div id="app">
你想要:{{x}}
<hr/>
<select v-model="x">
<option value=""> - </option>
<option value="1">抽烟</option>
<option value="2">喝酒</option>
<option value="3">烫头</option>
</select>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
x: []
}
},
components: {}
};
</script>
复制代码
如果
v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
用 v-for
渲染的动态选项(多选也一样)
<template>
<div id="app">
你想要:{{x}}
<hr/>
<select v-model="x">
<option value=""> - </option>
<option v-for="item in array" :value="item.value" :key="item.value">{{item.text}}</option>
</select>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
array: [
{text:'抽烟', value:1},
{text:'喝酒', value:2},
{text:'烫头', value:3}
],
x: ""
}
},
components: {}
};
</script>
复制代码
多选时
绑定到一个数组
<template>
<div id="app">
你想要:{{x}}
<hr/>
<select multiple v-model="x">
<option value=""> - </option>
<option v-for="item in array" :value="item.value" :key="item.value">{{item.text}}</option>
</select>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
array: [
{text:'抽烟', value:1},
{text:'喝酒', value:2},
{text:'烫头', value:3}
],
x: []
}
},
components: {}
};
</script>
复制代码
+shift
连选,+ctrl
多选,再按一次+ctrl
取消(因为很多用户不会这样用,所以一般不这样做多选框)
form
<template>
<div id="app">
登录
<form @submit.prevent="onSubmit">
<label>
<span>用户名</span>
<input type="text" v-model="user.username" />
</label>
<label>
<span>密码</span>
<input type="password" v-model="user.password" />
</label>
<button type="submit">登录</button>
</form>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
user:{
username: '',
password: ''
}
}
},
methods:{
onSubmit(){
console.log(this.user);
}
},
components: {}
};
</script>
复制代码
修饰符
.lazy
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转为在 change
事件_之后_进行同步。
回顾下
input
事件和change
事件
input
事件,键盘、鼠标、任何输入设备的输入change
事件,只在 input 失去焦点时触发
// 比如将上面这个例子的 <input /> 加上 .lazy
<input type="text" v-model="user.username" />
复制代码
加之前
加之后
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符。
这通常很有用,因为即使在 type="number"
时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat()
解析,则会返回原始的值。
// 还是改上面那个例子
<template>
<input type="text" v-model.number="user.username" />
// input 加 .number 修饰符
...
</template>
<script>
export default {
...
data() {
...
user:{
username: 0,
// username 改为 number 类型
password: ''
}
}
...
</script>
复制代码
返回效果
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符。
// 改上面例子
<input type="text" v-model.trim="user.username" />
复制代码
改前
改后
自定义组件的 v-model
一个组件上的 v-model
默认会利用名为 value
的 prop 和名为 input
的事件。
例子:
// 还是上面的例子 App.vue
<template>
<div id="app">
{{user}}
<hr />
登录
<form @submit.prevent="onSubmit">
<label>
<span>用户名</span>
<MyInput v-model="user.username" />
<MyInput :value="user.username" @input="user.username = $event" /> // 相当于使用 v-model
</label>
<label>
<span>密码</span>
<input type="password" v-model="user.password" />
</label>
<button type="submit">登录</button>
</form>
</div>
</template>
<script>
import MyInput from "@/MyInput";
export default {
name: 'App',
components: {MyInput},
data() {
return {
user:{
username: '',
password: ''
}
}
},
methods:{
onSubmit(){
console.log(this.user);
}
},
};
</script>
复制代码
// src 目录下再新建一个 MyInput.vue,将此组件导入上面组件
<template>
<div class="red wrapper">
<input :value="value" @input="$emit('input',$event.target.value)" />
</div>
</template>
<script>
export default {
name: 'MyInput',
props: {
value: {
type: String
}
}
}
</script>
<style scoped>
.red {
background: red;
}
.wrapper {
display: inline-block;
}
</style>
复制代码
效果
使用 ant-design-vue
Ant Design 分别提供了 Vue 和 React 的UI组件库
安装 antd
yarn add ant-design-vue
复制代码
修改 main.js 引入 antd
// 完整引入
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
Vue.use(Antd);
复制代码
官方也提供了局部导入组件的方法,在此不做赘述
使用组件
这里练习一下使用组件,以form表单为例
注意要将 XML 和 JS 的内容都引入,否则会报错。
修改后代码:
<template>
<div id="app">
<a-form
id="components-form-demo-normal-login"
:form="form"
class="login-form"
@submit="handleSubmit"
>
<a-form-item>
<a-input
v-decorator="[
'username',
{ rules:
[
{require: true, message: '请填写用户名'}
]
},
]"
placeholder="用户名"
>
<a-icon slot="prefix" type="user" style="color: rgba(0,0,0,.25)" />
</a-input>
</a-form-item>
<a-form-item>
<a-input
v-decorator="[
'password',
{ rules:
[
{ required: true, message: '请填写密码' },
{ min: 8, message: '密码最少8个字符' },
{pattern: /[a-zA-Z]/, message: '必须包含至少一个字母'}
]
},
]"
type="password"
placeholder="密码"
>
<a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)" />
</a-input>
</a-form-item>
<a-button type="primary" html-type="submit" class="login-form-button">
Log in
</a-button>
</a-form>
</div>
</template>
<script>
export default {
name: 'App',
beforeCreate() {
this.form = this.$form.createForm(this, { name: 'normal_login' });
},
methods: {
handleSubmit(e){
e.preventDefault();
this.form.validateFields((err, values) => {
if (!err) {
console.log('Received values of form: ', values);
}
});
}
}
};
</script>
复制代码
效果: