前言
组件间的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,接下来,我们就悉数给大家展示所有 Vue 组件之间的通信方式。
通信方案
- Props传递数据 (常用)
- $emit (组件封装用的较多)
- attrs & listeners
- Provide & Inject
- Ref使用
- EventBus
- Vuex通信
Props传递数据
简单来说,我们可以通过 Prop 向子组件传递数据。用一个形象的比喻来说,父子组件之间的数据传递相当于自上而下的下水管子,只能从上往下流,不能逆流。
父组件代码演示
子组件代码演示
$emit使用
父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。
父组件代码演示
子组件代码演示
$attrs 和 $listeners
第一种方式处理父子组件之间的数据传输有一个问题:如果多层嵌套,父组件A下面有子组件B,组件B下面有组件C,这时如果组件A想传递数据给组件C怎么办呢?
如果采用第一种方法,我们必须让组件A通过prop传递消息给组件B,组件B在通过prop传递消息给组件C;要是组件A和组件C之间有更多的组件,那采用这种方式就很复杂了。从Vue 2.4开始,提供了$attrs和$listeners来解决这个问题,能够让组件A之间传递消息给组件C。
$attrs
批量向下传入属性
<Son2 name="小文强" age="10"></Son2>
<!-- 可以在son2组件中使用$attrs属性,可以将属性继续向下传递 -->
<div>
儿子2: {{$attrs.name}}
<Grandson2 v-bind="$attrs"></Grandson2>
</div>
<template>
<div>孙子:{{$attrs}}</div>
</template>
$listeners
<Son2 name="小文强" age="10" @click="()=>{this.mny = 500}"></Son2>
<!-- 可以在son2组件中使用listeners属性,可以将方法继续向下传递 -->
<Grandson2 v-bind="$attrs" v-on="$listeners"></Grandson2>
<button @click="$listeners.click()">更改</button>
Provide 和 Inject
父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
Provide
provide() {
return { parentMsg: "父亲" };
},
Inject
inject: ["parentMsg"] // 会将数据挂载在当前实例上
Ref使用
Ref可以直接获取组件的实例
<Grandson2 v-bind="$attrs" v-on="$listeners" ref="grand2"></Grandson2>
mounted() { // 获取组件定义的属性
console.log(this.$refs.grand2.name);
}
EventBus
思路就是声明一个全局Vue实例变量 EventBus , 把所有的通信数据,事件监听都存储到这个变量上。这样就达到在组件间数据共享了,有点类似于 Vuex。但这种方式只适用于极小的项目,复杂项目还是推荐 Vuex。
Vue.prototype.$bus = new Vue();
Son2组件和Grandson1相互通信
mounted() {
this.$bus.$on("my", data => {
console.log(data);
});
},
mounted() {
this.$nextTick(() => {
this.$bus.$emit("my", "我是Grandson1");
});
},
Vuex处理组件之间的数据交互
如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。