想实现双向绑定是为了避免下面的情况:比如子组件更新数据后,父组件没有对应的更新,造成错误。或者页面比较复杂的时候,遗漏手动更新。
所以需要双向同步,核心就是自动更新值到父组件
常见的双向绑定
常见的双向绑定,就是input中的v-model
<input v-model="searchText" />
这个searchText在data中声明,然后使用v-model绑定,效果就是:在input值改变的时候,searchText的值同步改变;手动改变searchText值的时候,input中的显示也跟随改变
实现原理:
根据官网的介绍,实现原理是,这个代码被编译的时候,编译器对代码进行了展开,等价于
<input
:value="searchText"
@input="searchText = $event.target.value"
/>
:value指向的是input展示的属性,手动改变属性值,会改变input的展示内容
input输入值的时候,触发input的事件,会将输入结果赋值给input展示的属性searchText,改变input的展示内容
所以当主动改变searchText,或者使输入内容的时候,都会改变input的展示内容。实现了双向绑定
父子组件属性的双向绑定
在组件定义prop属性,接收父组件传递的值,是单向的,子组件不能修改prop属性,否则会警报
那么要想父子同步,常用的方式
$emit
子组件prop接收值,data中声明自定义变量接收prop属性的值
在需要改变的时候,通过$emit方法,触发指定的父组件的函数,将变化后的值传递过去,父组件更新值
简单来说,可以这么实现双向绑定,比如
- 父组件通过prop传递给子组件初始值
- 子组件自定义属性接收初始值,当需要改变的时候,改变自定义属性的值,然后通过$emit传递给父组件
- 父组件拿到新值,更新自己传递给子组件的值
这样,双方的数据就是一致的了
其他方式
.sync
vue2中提供了.sync的方式来进行双向同步
原理与上面的$emit是一样的,只不过不需要在父组件写指定的函数,自己更新数据了,而是只需要在子组件中指定函数与新值
例子如下:
父组件
父组件写法与之前不同的是,在需要双向绑定的数据后追加.sync,比如
<child :name="childName" :sdata.sync="syncData"></child>
<script>
export default {
data() {
return {
syncData: 'ppp',
}
},
...
其中sdata就是子组件在prop中声明的要接收父组件传递值的字段,.sync表示这个字段是要双向绑定的
子组件
子组件中,写法基本不变,$emit函数变化
1: 在props中声明要接收的数据
props:{
sdata:{
type: String,
default: ''
}
},
2:在数据变化后,指定更新函数,该函数会自动更新同步父组件关联的属性值。
changeValue(){
this.sdata = 'ttt'
this.$emit('update:sdata', this.sdata)
}
注意函数的写法:this.$emit(‘update:xxx’: newValue)
组件v-model
vue2
与.sync的表现是一样的,不需要在父组件写指定的函数,自己更新数据了,只是写法变化了一些
例子:
子组件中:
<button class="btn" @click="changeValue">{{childValue}}</button>
...
props:{
// 声明要从父组件传递过来的属性
fatherValue:{
type:String,
default:"",
}
},
// 自定义model
model:{
prop: 'fatherValue', // 属性
event: 'childValueChange' // 触发事件,触发这个事件,会将传递的value赋值给指定的属性prop
},
data(){
return{
childValue: this.fatherValue // 初始化接收的值
}
},
methods:{
changeValue(){
this.childValue = 'childChange'
this.$emit('childValueChange', this.childValue) // 触发指定事件,传递value,会更新父组件的值
}
}
父组件中:
<child v-model="fatherValue"></child>
效果,在浏览器的vue插件中查看数据
按钮点击前:
点击按钮后
说明父组件的数据同步更新了
通过后续的尝试,发现,v-model的值是Object类型的也可以
v-model与.sync写法的一些区别
主要体现在:
- 父组件中,引用数据一个是v-model,一个是:xxx.sync
- 子组件中,v-model的方式,需要创建一个自定义model,指定要同步的属性和触发函数名称
- 使用this.$emit()指定触发的函数不同,.sync中的是 ‘update:xxx’,而v-model中的是自定义model中指定的函数名称
最后,在vue2中,v-model只能写一个,而.sync可以有多个
vue3
父组件使用v-moel,vue2中只允许写一个v-model,在vue3中,允许写多个v-model
父组件中使用: v-model:xxx来绑定值
<UserName
v-model:first-name="first"
v-model:last-name="last"
/>
子组件声明的时候,不使用props+model了,而是使用props+emits:
export default {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
}
触发原理与vue2中的一样,指定事件会将传递的value赋值给指定的属性prop