欢迎大家订阅【Vue2+Vue3】入门到实践 专栏,开启你的 Vue 学习之旅!
1 v-model原理
1. 基本原理
v-model
本质上是一个语法糖,它将 value
属性 和 input
事件 的绑定合并为一个指令。
对于输入框这种常见的表单元素,v-model
会自动为你绑定 value
属性和 input
事件,实现数据双向绑定。
2. 作用
提供数据的双向绑定
:value
:数据变,视图跟着变@input
:视图变,数据跟着变
【示例】
<template>
<div id="app" >
<input v-model="msg1" type="text">
<input :value="msg2" type="text">
</div>
</template>
<script>
export default {
data(){
return{
msg1:'',
msg2:''
}
}
}
</script>
<style>
</style>
【详解】
①v-model="msg1"
:msg1
会和第一个 <input>
元素的 value
进行双向绑定。
- 当用户在输入框中输入内容时,
msg1
会更新为输入的值。 - 如果
msg1
改变,输入框的值会同步更新。
②:value="msg2"
:第二个 <input>
通过 :value
绑定 msg2
,但是它并没有绑定 input
事件。
msg2
只是将初始值传递给输入框,但当用户输入新的内容时,msg2
的值不会更新。- 如果希望
msg2
随着用户输入动态更新,还需要显式地处理输入事件。
【运行结果】
【优化】
<template>
<div id="app" >
<input v-model="msg1" type="text">
<!-- 模板中获取事件的形参 -> 通过 $event 获取 -->
<input :value="msg2" @input="msg2 = $event.target.value" type="text">
</div>
</template>
:value="msg2" @input="msg2 = $event.target.value"
:第二个 <input>
不仅绑定了 msg2
的初始值(通过 :value="msg2"
),还显式地绑定了 input
事件。
- 每当用户输入时,
@input
事件会触发,并通过$event.target.value
获取输入框的值。 - 通过
msg2 = $event.target.value
,更新msg2
的值,从而实现双向绑定。 - 该方式使得
msg2
的值能够随着用户的输入动态更新。
【运行结果】
3. 注意事项
v-model
在不同类型的表单元素上工作时,底层的实现机制会有所不同。
- 文本框 (
<input type="text">
):绑定value
属性和input
事件。 - 复选框 (
<input type="checkbox">
):绑定checked
属性和change
事件,处理布尔值或数组。 - 单选框 (
<input type="radio">
):绑定checked
属性和change
事件,处理选中的值。 - 下拉框 (
<select>
):绑定value
属性和change
事件,处理选中的值。
Vue 会根据表单元素的不同,自动选择合适的属性和事件来实现数据的双向绑定,从而简化了开发者的工作。
2 表单类组件封装
1. 需求目标
实现子组件和父组件数据的双向绑定 。
2. 示例代码
父组件App.vue
<template>
<div class="app">
<BaseSelect></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '102',
}
},
components: {
BaseSelect,
},
}
</script>
<style>
</style>
子组件BaseSelect.vue
<template>
<div>
<select>
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
【代码分析】
- 父组件:定义了一个
selectId
,用于存储当前选中的城市 ID,但没有将该值传递给子组件。 - 子组件:
<select>
元素的值没有任何绑定,用户在子组件中选中城市时,父组件中的 selectId 不会自动更新。
【暴露得问题】
父组件和子组件之间的数据没有双向绑定,修改子组件中的选择不会反映到父组件的数据中。
【优化】
父组件App.vue:
<template>
<div class="app">
<BaseSelect
:cityId="selectId"
@changeId="selectId=$event"
></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '102',
}
},
components: {
BaseSelect,
},
}
</script>
<style>
</style>
子组件BaseSelect.vue:
<template>
<div>
<select :value="cityId" @change=handleChange>
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
props:{
cityId:String
},methods:{
handleChange(e){
this.$emit('changeId',e.target.value)
}
}
}
</script>
<style>
</style>
【优化思路】
手动实现双向绑定:
- 父组件:
selectId
被传递给子组件BaseSelect
,并通过@changeId
监听子组件发出的changeId
事件,将子组件的选中值($event)
更新到父组件的selectId
上。 - 子组件:子组件通过
props
接收来自父组件的cityId
,并将select
元素的value
属性与其绑定,用户选择城市时,触发@change
事件,使用this.$emit('changeId', e.target.value)
将选中的值传递回父组件。
【运行结果】
- 实现了父子组件之间的数据双向绑定。
- 当用户在子组件中选择不同的城市时,selectId 会自动更新。
- 如果 selectId 在父组件中发生变化,子组件的选择框也会同步更新。
3 v-model简化代码
1. 目标
父组件通过 v-model
简化代码,实现子组件和父组件数据 双向绑定
2. 简化思路
v-model
其实就是 :value
和 @input
事件的简写
- 子组件:
props
通过value
接收数据,事件触发input
- 父组件:
v-model
直接绑定数据
3. 示例代码
父组件App.vue
<template>
<div class="app">
<!-- v-mdel= :value +@input-->
<BaseSelect
v-model="selectId"
></BaseSelect>
</div>
</template>
<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
data() {
return {
selectId: '102',
}
},
components: {
BaseSelect,
},
}
</script>
<style>
</style>
子组件BaseSelect.vue
<template>
<div>
<select :value="value" @change=handleChange>
<option value="101">北京</option>
<option value="102">上海</option>
<option value="103">武汉</option>
<option value="104">广州</option>
<option value="105">深圳</option>
</select>
</div>
</template>
<script>
export default {
props:{
value:String
},methods:{
handleChange(e){
this.$emit('input',e.target.value)
}
}
}
</script>
<style>
</style>
使用 v-model
实现双向绑定:
- 父组件:通过
v-model="selectId"
将selectId
绑定到子组件的value
上。
子组件:接收一个名为value
的prop
,并使用:value="value"
来将父组件的selectId
传递给<select>
元素。当选择发生变化时,子组件会触发input
事件,父组件通过v-model
自动接收更新后的值。
【运行结果】