这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战
在Vue的组件通信过程中,除了之前讲到的 父子组件通信,本文讲解一下 Vue 项目中的 非父子组件之间的传值方式
事件总线 bus
vue官网指出,可以使用一个空vue实例作为事件中央线,非父子组件之间的通信,必须要有公共的实例,才能使用 $emit 和 $on 传递数据参数,实现组件之间的通信
公共实例文件bus.js,作为公共数控中央总线
import Vue from "vue";
export default new Vue();
一个组件A
import Bus from '../bus.js';
export default {
name: 'aaa',
data () {
return {
value: 'aaa.vue组件!'
}
},
methods:{
update(){// 定义update方法,并将msg通过txt传给另一个组件
Bus.$emit('txt',this.value);
}
}
}
一个组件B
import Bus from '../bus.js';
export default {
name: 'bbb',
data () {
return {
value:''
}
},
mounted:function(){
Bus.$on('txt',function(val){//监听aaa组件的txt事件
this.value = val
});
}
}
这样就可以在两个没有父子关系的组件中,通过第三者bus.js来获取到第一个组件的value
兄弟组件之间与父子组件之间的数据交互,两者相比较,兄弟组件之间的通信其实和子组件向父组件传值有些类似,其实他们的通信原理都是相同的
例如子向父传值也是on的形式,只是没有eventBus,其实是父组件来充当了bus这个事件总线的角色
$attrs/listeners
$attrs 和 listeners 的方式用于多级组件间传值的问题
在对一些组件进行二次封装时可以方便传值,组件A传递到组件C,使用组件B作为桥梁A-B-C
一个组件A (app.vue
<template>
<div id="app">
<child1
:p-child1="child1"
:p-child2="child2"
v-on:test1="onTest1"
v-on:test2="onTest2">
</child1>
// 监听了两个事件,可以在B组件或者C组件中直接触发
</div>
</template>
<script>
import Child1 from './Child1.vue';
export default {
data () {
return {};
},
components: { Child1 },
methods: {
onTest1 () {
console.log('test1 running...');
},
onTest2 () {
console.log('test2 running');
}
}
};
</script>
一个组件B (child1
<template>
<div class="child-1">
<p>in child1:</p>
<p>props: {{pChild1}}</p>
<p>$attrs: {{$attrs}}</p>
<hr>
<child2 v-bind="$attrs" v-on="$listeners"></child2>
// C组件中能直接触发test的原因在于 B组件调用C组件时 使用 v-on 绑定了$listeners 属性
// 通过v-bind 绑定$attrs属性,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的)
</div>
</template>
<script>
import Child2 from './Child2.vue';
export default {
props: ['pChild1'],
data () {
return {};
},
inheritAttrs: false,
components: { Child2 },
mounted () {
this.$emit('test1');
}
};
</script>
一个组件C
<template>
<div class="child-2">
<p>in child2:</p>
<p>props: {{pChild2}}</p>
<p>$attrs: {{$attrs}}</p>
<hr>
</div>
</template>
<script>
export default {
props: ['pChild2'],
data () {
return {};
},
inheritAttrs: false,
// 如果不想在dom上出现属性,可设置interitAttrs: false
mounted () {
this.$emit('test2');
}
};
</script>
如果组件C中有props属性接受的对象的化,组件A传递的对象就会被自动过滤掉
Vuex
对于更复杂的情况,Vue也有提供更复杂的状态管理模式Vuex来进行处理