vue深层的组件间通信
需求:当我们有一个组件的层级结构为 组件1 >> 组件2 >> 组件3的时候怎样通信最好
方案
1. 通过最常用的props和$emit来实现组件间的传值
缺点:随着组件的嵌套的层级增多,每层的父组件都要监听子组件$emit发射的事件,太繁琐
2. 通过this.$parent和this.$children来相互调用组件的值或方法实现通信
缺点:这个可以避免props和$emit的问题,但是假设我想在组件3用引用组件1的方法来改变某一个变量时,这时我们用这样写this.$parent.$parent,这样就很鸡肋,而且还必须管理父组件的层级,太不灵活
3. 通过eventBus来实现多层组件间的数据共享
分析:eventBus实际上就是通过将共享的变量存在新建的一个vue的实例上,然后通过该实例的$emit和$on去实现数据的传递
代码:
eventBus.js
import Vue from 'vue'
export default new Vue()
组件1
import bus from 'common/js/eventBus'
export default {
methods: {
busEmit() {
bus.$emit('busEmit', '我是组件1发送的值')
}
},
created() {
this.busEmit()
}
}
组件3
import bus from 'common/js/eventBus'
export default {
created() {
bus.$on('busEmit', (data) => {
console.log(data)
})
}
}
优势:对于某一个多层嵌套的组件而言,他不会太繁琐
缺点:但是对于有多个这种组件都要做多层件的传值时,由于所有共享值都是有这一个vue的实例去发送的,因此这种方案就不利于项目后期的状态维护,且耦合度也比较高
4. 通过vuex这个状态管理来共享数据
分析:vuex可能是最常用的跨组件和跨页面的通信方式了,它相比于eventBus的方案,由于它可以将不同模块的数据进行模块化管理,通过namespace的方式访问,这使得其可维护性相对于前者比较高,并且也降低了数据转态之间的耦合
缺点:假设如果有上百个组件都是这种嵌套的情况,那vuex也就要维护这些组件的一些数据和状态,组件内部要不停的去通过mutations,actions操作数据的变化,写法上就太麻烦了
5. 通过provide/inject来跨组件通信
代码
组件A
<template>
<div>
{{name}}-{{age}}
<b-comp />
</div>
</template>
<script>
import BComp from './b.vue'
export default {
provide() {
return {
compA: this,
compA_age: this.age
}
},
data() {
return {
name: '我是组件A',
age: 18
}
},
components: {
BComp
},
methods: {
test() {
console.log('我是a组件的测试方法')
}
}
}
</script>
组件b
<template>
<div>
{{name}}
<c-comp />
</div>
</template>
<script>
import CComp from './c.vue'
export default {
provide() {
return {
compB_name: this.name,
compB: this
}
},
inject: {
getCompAdata: {
from: 'compA',
default: null
},
getCompAage: {
from: 'compA_age',
default: 19
}
},
data() {
return {
name: '我是组件B'
}
},
components: {
CComp
},
created() {
console.log(this.getCompAdata.name)
this.getCompAdata.test()
console.log(this.getCompAage) // 如果a组件中没有compA_age则会显示19
this.getCompAdata.name = '我是组件A change by CompB' // 修改会影响a组件,和props传入对象一样,但是会抛出警告,证明他与props一样数据是单向传递的
this.getCompAage = '18 change by CompB'
}
}
</script>
组件c
<template>
<div>
我是组件C
</div>
</template>
<script>
export default {
inject: {
getCompB_name: {
from: 'compB_name',
default: ''
},
getCompB: {
from: 'compB',
default: ''
},
getCompA: {
from: 'compA',
default: ''
}
},
data() {
return {
name: 'C'
}
},
created() {
console.log('c组件访问b组件的name属性:', this.getCompB_name)
console.log('c组件访问b组件的this对象:', this.getCompB)
console.log('c组件访问b组件的this对象调用组件A的name:', this.getCompB.getCompAdata.name)
console.log('c组件访问a组件的name:', this.getCompA.name)
}
}
</script>
总结:这钟是目前来说比较好的方式,因为每个嵌套组件的状态是相对独立的,由他们自身去控制和维护,在写法上也比较简单,并且可以通过from字段定义引用的来源,以此来减少耦合
6. 在组件中使用inheritAttrs和$attrs传递数据
组件a
<template>
<div>
{{name}}-{{age}}-stars:{{obj.star}}
<b-comp :name="name" :obj="obj" :age="age" :test="test"/>
</div>
</template>
<script>
import BComp from './b.vue'
export default {
data() {
return {
name: '我是组件A',
age: 18,
obj: {
star: 2300
}
}
},
components: {
BComp
},
methods: {
test() {
console.log('我是a组件的测试方法')
}
}
}
</script>
组件b
<template>
<div>
{{name}}
<c-comp :name="name" v-bind="$attrs"/>
</div>
</template>
<script>
import CComp from './c.vue'
export default {
inheritAttrs: false,
data() {
return {
name: '我是组件B'
}
},
components: {
CComp
},
created() {
console.log('组件b', this.$attrs)
this.$attrs.test()
this.$attrs.obj.star = 4000
this.$attrs.age = 100
}
}
</script>
组件c
<template>
<div>
我是组件C
</div>
</template>
<script>
export default {
inheritAttrs: false,
props: {
obj: {
type: Object,
default() {
return {}
}
}
},
data() {
return {
name: 'C'
}
},
created() {
console.log('组件c的',this.$attrs)
}
}
</script>
总结:
这种方式值的传递也是单向的,当传递一个引用类型的数据是,在子组件修改此参数数据,也会影响父级组件,但是它不会报错,当你传入的参数与子组件内部的props同名是,此时的$attrs会将该重复的数据去除掉,如果你中间的组件传一个名字相同的参数时,此时后面的会覆盖前面的同名参数的值。
[vue.md](./upload/201911/23/15744928021101847029.md)
网友评论