Vue基础--Vue中的双向绑定v-model指令
v-model使用详解
一、v-model的作用和使用场景
1.1 v-model指令介绍
-
期望的绑定值类型:根据表单输入元素或组件输出的值而变化
-
可以下下面元素使用:
<input>
<select>
<testarea>
components
<checkbox>
<radio>
<select>
表单输入元素都是可以使用的
-
v-model支持的修饰符:
.lazy
——监听change
事件而不是input
.number
——将输入的合法符串转为数字.trim
—移除输入内容两端空格
1.2 v-model指令的作用
在表单输入元素或组件上创建双向绑定。
它会根据控件类型自动选取正确的方法来更新元素。
它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
毕竟表单提交是开发中非常常见的功能,也是和用户交互的重要手段。
用户在登录、注册时需要提交账号密码,检索、新建、更新数据时,需要提交数据,这些都离不开表单提交。
1.3 什么是双向绑定
Vue
中的的双向数据绑定是指model
模型(Vue
中data
下定义的变量)和view
(视图)的双向绑定。
其中一个发生改变,另一个也会更新改变。
但是更通俗和常用的讲就是当表单元素的值发生变化时。和它绑定的Vue
中的data
变量也发生改变。,
二、v-model的基本使用
2.1 代码示例和解析
<div id="app">
<!-- 1.使用v-model实现input的双向绑定 -->
<input type="text" v-model="message">
<h2>input: {{message}}</h2>
<hr>
<!-- 2.使用v-model实现textarea的双向绑定 -->
<textarea cols="30" rows="10" v-model="content"></textarea>
<h2>textarea: {{content}}</h2>
<hr>
<!-- 3.使用v-model实现checkbox的双向绑定 -->
<!-- 3.1 checkbox单选框: 绑定到属性中的值是一个Boolean -->
<!-- label的作用是点击label中的文本时,相当于点击到绑定的input元素 -->
<label for="agree">
<input id="agree" type="checkbox" v-model="isAgree"> 同意协议
</label>
<h2>checkbox单选: {{isAgree}}</h2>
<hr>
<!-- 3.2 checkbox多选框: 绑定到属性中的值是一个Array -->
<!-- checkbox单选框; 绑定到属性中的值是单选框的value -->
<div class="hobbies">
<h2>请选择你的爱好:</h2>
<label for="sing">
<input id="sing" type="checkbox" v-model="hobbies" value="sing"> 唱
</label>
<label for="jump">
<input id="jump" type="checkbox" v-model="hobbies" value="jump"> 跳
</label>
<h2>爱好: {{hobbies}}</h2>
</div>
<hr>
<!-- 4.使用v-model实现radio的双向绑定 -->
<!-- radio单选框: 绑定到属性中的值是单选框的value -->
<div class="gender">
<label for="male">
<input id="male" type="radio" v-model="gender" value="male"> 男
</label>
<label for="female">
<input id="female" type="radio" v-model="gender" value="female"> 女
</label>
<h2>性别: {{gender}}</h2>
</div>
<hr>
<!-- 4.使用v-model实现select的双向绑定 -->
<!-- 4.1 select单选框的值绑定 -->
<select v-model="fruit">
<option v-for="item in allFruits" :key="item.value" :value="item.value">
{{item.text}}
</option>
</select>
<h2>单选: {{fruit}}</h2>
<!-- 4.2 select多选框的值绑定 -->
<select multiple size="3" v-model="fruits">
<option v-for="item in allFruits" :key="item.value" :value="item.value">
{{item.text}}
</option>
</select>
<h2>多选: {{fruits}}</h2>
<hr>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data() {
return {
message: "Hello Model", //v-model绑定的input数据
content: "", //v-model绑定的textarea数据
isAgree: false, //v-model绑定的checkbox单选框数据
hobbies: [] //v-model绑定的checkbox多选框数据
gender: "female" //v-model绑定的radio单选框数据
fruit: "orange", //v-model绑定的select单选框数据
fruits: [], //v-model绑定的select多选框数据
allFruits: [
{ value: "apple", text: "苹果" },
{ value: "orange", text: "橘子" },
{ value: "banana", text: "香蕉" },
], // 水果
}
}
})
// 2.挂载app
app.mount("#app")
</script>
可以看到,使用v-model
的方式非常简单:
- 在支持
v-model
的表单输入元素上加上v-model
指令 - 在
Vue
的data
选项API
中定义数据变量,赋值给v-model
就实现了数据的双向绑定
这些也都是对基础的表单元素进行操作。实际开发大多会使用各种各样的组件库开发。
但是使用的方式和原理都是一样的。
2.2 v-model和值绑定:
所谓值绑定,其实并不是很高深的东西,只是Vue
官方提供的一个概念。
意思就是表单元素中的value
值并不是写死的,而是来自于服务器或者配置文件。
我们就可以先将值请求下来,绑定到data返回的对象中,
再使用条件渲染指令和列表渲染指令把值动态绑定到表单元素上,最后通过v-bind
指令来进行绑定。
这个过程就是值绑定。
例如上面代码中select
的绑定方式:
<div id="app">
<!-- select单选框的值绑定 -->
<select v-model="fruit">
<option v-for="item in allFruits" :key="item.value" :value="item.value">
{{item.text}}
</option>
</select>
<h2>单选: {{fruit}}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data() {
return {
fruit: "orange", //v-model绑定的select单选框数据
allFruits: [
{ value: "apple", text: "苹果" },
{ value: "orange", text: "橘子" },
{ value: "banana", text: "香蕉" },
], // 水果
}
}
})
// 2.挂载app
app.mount("#app")
</script>
在这段代码中,<select>
中<option>
的值并不是直接写死在表单元素上的。
它们的值来自allFruits
数组,这个数组可能来自于服务器或者配置文件。
这也是开发中常见的情况。
三、v-model的修饰符
3.1 v-model支持的修饰符:
-
.lazy
——监听change
事件而不是input
-
默认情况下,
v-model
在进行双向绑定时,绑定的是input事件。那么会在每次内容输入后就将最新的值和绑定的属性进行同步。
-
如果在
v-model
后跟上lazy
修饰符,那么会将绑定的事件切换为 change 事件。只有在提交(或者回车)时才会触发。
-
-
.number
——将输入的合法符串转为数字 -
.trim
——移除输入内容两端空格
3.2 代码示例
<div id="app">
<!-- 1.lazy: 绑定change事件 -->
<input type="text" v-model.lazy="message">
<h2>message: {{message}}</h2>
<hr>
<!-- 2.number: 自动将内容转换成数字 -->
<!--
这里有个冷知识:
vue2.x中 如果input中输入的是数字,v-model也会自动把数字转为字符串,除非加上.number修饰符
vue2.x中 如果input中输入的是数字,将可以直接获取到数字,而不用再加.number修饰符
-->
<input type="text" v-model.number="counter">
<h2>counter:{{counter}}-{{typeof counter}}</h2>
<input type="number" v-model="counter2">
<h2>counter2:{{counter2}}-{{typeof counter2}}</h2>
<hr>
<!-- 3.trim: 去除收尾的空格 -->
<input type="text" v-model.trim="content">
<h2>content: {{content}}</h2>
<hr>
<!-- 4.使用多个修饰符 -->
<input type="text" v-model.lazy.trim="content">
<h2>content: {{content}}</h2>
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
// data: option api
data() {
return {
message: "Hello Vue",
counter: 0,
counter2: 0,
content: ""
}
},
watch: {
content(newValue) {
console.log("content:", newValue)
}
}
})
// 2.挂载app
app.mount("#app")
</script>
四、手写v-model原理
官方文档中有提到,v-model
的原理其实是背后有两个操作:
-
v-bind
绑定value
属性的值 -
v-on
绑定input
事件监听到函数中,函数会获取最新的值赋值到绑定的属性中
依旧上面的原理,可以手写一个v-model
的实现:
<div id="app">
<!--
手动的实现双向绑定:
先使用v-bind语法糖把message绑定到input的value上
再使用v-on语法糖绑定input元素的input事件
-->
<input type="text" :value="message" @input="change">
</div>
<script src="../lib/vue.js"></script>
<script>
// 1.创建app
const app = Vue.createApp({
data() {
return {
message: "Hello Model"
}
},
methods: {
change(event) {
// 获取当前input表单元素中的内容
this.message = event.target.value
}
}
})
// 2.挂载app
app.mount("#app")
</script>
至于如果程序中的message
发送变化,Vue
会有另一部分代码监听数据的变化,并把变化的数据渲染到视图上。
再结合v-model
就完成了Vue
中数据的双向绑定。
五、v-model用于组件上
5.1 v-model在组件上的基本使用
通过上面的说明可以知道,表单元素上的v-model
使用方式如下:
<input v-model="searchText" />
上面的代码其实等价于下面这段 (编译器会对 v-model
进行展开):
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
而当使用在一个组件上时,v-model
会被展开为如下的形式:
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
因此<CustomInput>
组件内部需要做两件事:
-
将内部原生
input
元素的value
属性绑定到modelValue
的prop
组件上 -
输入新的值时在
input
元素上触发update:modelValue
事件
<!-- CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>
5.2 自定义组件中处理v-model 的参数
默认v-model
在组件上都是使用 modelValue
作为 prop,并以 update:modelValue
作为对应的事件。
我们可以通过给 v-model
指定一个参数来更改这些名字。
<MyComponent v-model:title="bookTitle" />
此时子组件应声明一个 title
prop,并通过触发 update:title
事件更新父组件值:
<!-- MyComponent.vue -->
<template>
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)"
/>
</template>
<script>
export default {
props: ['title'],
emits: ['update:title']
}
</script>
5.3 自定义组件中处理多个v-model 绑定
我们可以在一个组件上创建多个 v-model
双向绑定,每一个 v-model
都会同步不同的prop
。
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
<script>
export default {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
}
</script>
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
5.4 自定义组件中处理 v-model 修饰符
v-model
有一些内置的修饰符。例如 .trim
,.number
和 .lazy
。
在某些场景下,你可能想要一个自定义组件的 v-model
支持自定义的修饰符。
例如创建一个自定义的修饰符 capitalize
,它会自动将 v-model
绑定输入的字符串值第一个字母转为大写:
<MyComponent v-model.capitalize="myText" />
组件的 v-model
上所添加的修饰符,可以通过 modelModifiers
prop 在组件内访问到。
在下面的组件中,声明了 modelModifiers
这个 prop
,它的默认值是一个空对象:
<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
created() {
console.log(this.modelModifiers) // { capitalize: true }
}
}
</script>
<template>
<input
type="text"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
注意:
组件
prop
中的modelModifiers
的 包含了capitalize
且其值为true
。因为它在模板中的
v-model
绑定上被使用了。
有了 modelModifiers
这个 prop,我们就可以在原生事件侦听函数中检查它的值。
然后决定触发的自定义事件中要向父组件传递什么值。
<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
methods: {
emitValue(e) {
let value = e.target.value
// 如果有capitalize的值为true,则做一些对应的操作
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
}
}
</script>
<template>
<input type="text" :value="modelValue" @input="emitValue" />
</template>
对于又有参数又有修饰符的 v-model
绑定,生成的 prop 名将是 arg + "Modifiers"
。
示例:
<MyComponent v-model:title.capitalize="myText">
export default {
props: ['title', 'titleModifiers'],
emits: ['update:title'],
created() {
console.log(this.titleModifiers) // { capitalize: true }
}
}
六、v-model官方文档
https://cn.vuejs.org/api/built-in-directives.html#v-model
更多推荐
所有评论(0)