六种方式
1. props
/ $emit
适用于 父子组件通信
略…
2. ref
与 $parents
/ $children
适用于父子组件通信
不好维护,不推荐使用
3. EventBus
适用于 父子 隔代 兄弟组件通信
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件.
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
<!-- A.vue -->
<template>
<button @click="sendMsg()">-</button>
</template>
<script>
import { EventBus } from "../event-bus.js";
export default {
methods: {
sendMsg() {
EventBus.$emit("aMsg", '来自A页面的消息');
}
}
};
</script>
<!-- IncrementCount.vue -->
<template>
<p>{{msg}}</p>
</template>
<script>
import { EventBus } from "../event-bus.js";
export default {
data(){
return {
msg: ''
}
},
mounted() {
EventBus.$on("aMsg", (msg) => {
// A发送来的消息
this.msg = msg;
});
}
};
</script>
同理我们也可以在 B页面 向 A页面 发送消息。这里主要用到的两个方法:
// 发送消息
EventBus.$emit(channel: string, callback(payload1,…))
// 监听接收消息
EventBus.$on(channel: string, callback(payload1,…))
注意: 如果使用不善,EventBus
会是一种灾难,到底是什么样的“灾难”了?大家都知道vue是单页应用,如果你在某一个页面刷新了之后,与之相关的EventBus
会被移除,这样就导致业务走不下去。还要就是如果业务有反复操作的页面,EventBus
在监听的时候就会触发很多次,也是一个非常大的隐患。这时候我们就需要好好处理EventBus
在项目中的关系。通常会用到,在vue页面销毁时,同时移除EventBus
事件监听。
import { eventBus } from './event-bus.js'
EventBus.$off('aMsg', {})
//移除所有事件
EventBus.$off()
4. $attrs
/ $listeners
适用于隔代组件通信
$attrs
官网解释:包含了父作用域中不作为prop
被识别 (且获取) 的特性绑定 (class
和 style
除外)。当一个组件没有声明任何prop
时,这里会包含所有父作用域的绑定 (class
和style
除外),并且可以通过v-bind="$attrs"
传入内部组件——在创建高级别的组件时非常有用
接收除了props声明外的所有绑定属性(class、style除外)
$listeners
包含了父作用域中的 (不含native
修饰器的)v-on
事件监听器。它可以通过v-on="$listeners"
传入内部组件——在创建更高层次的组件时非常有用。
收除了带有.native事件修饰符的所有事件监听器
vue2.4以后,使用$attrs
,inheritAttrs
属性 能够使用简洁的代码,将A组件的数据传递给C组件. B组件上 绑定 v-on="$listeners"
, 在a组件中,监听C组件触发的事件。就能把C组件发出的数据,传递给A组件。
//A组件
<template>
<div>
<child-dom
:foo="foo"
:coo="coo"
v-on:upRocket="reciveRocket"
>
</child-dom>
</div>
</template>
<script>
import childDom from "@/components/ChildDom.vue";
export default {
name:'demoNo',
data() {
return {
foo:"Hello, world",
coo:"Hello,rui"
}
},
components:{childDom},
methods:{
reciveRocket(){
console.log("reciveRocket success")
}
}
}
</script>
//B组件
<template>
<div>
<p>foo:{{foo}}</p>
<p>attrs:{{$attrs}}</p>
<childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>
</div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
name:'child-dom'
props:["foo"],
inheritAttrs:false,
}
</script>
//C组件
<template>
<div>
<p>coo:{{coo}}</p>
<button @click="startUpRocket">我要发射火箭</button>
</div>
</template>
<script>
export default {
name:'childDomChild',
props:['coo'],
methods:{
startUpRocket(){
this.$emit("upRocket");
console.log("startUpRocket")
}
}
}
</script>
5. provide
/ inject
适用于 隔代组件通信
在Vue2.2.0之后,Vue提供了provide/inject
允许一个祖先组件向其所有子孙后代组件注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
也就是说,在父组件只要声明了provide
,在其子组件,孙组件,曾孙组件等能形成上下游关系的组件中交互,无论多深都能通过inject
来访问provider
中的数据。而不是局限于只能从当前父组件的prop
属性来获取。注意他只做祖先通后代的单向传递的一个办法。
-
provide
提供变量 :Object | () => Object
-
inject
注入变量:Array<string> | { [key: string]: string | Symbol | Object }
提示:provide和inject绑定并不是可响应的,这是刻意为之,然而如果你传入了一个可监听的对象,那么气对象的属性还是可监听的
//父组件
<template>
<div>
<p>{{ title }}</p>
<son></son>
</div>
</template>
<script>
import Son from "./son"
export default {
name: 'Father',
components: { Son },
// provide选项提供变量
provide: {
message: 'provided by father'
},
data () {
return {
title: '父组件'
}
},
methods: { ... }
}
</script>
//子组件
<template>
<div>
<p>{{ title }}</p>
<grand-son></grand-son>
</div>
</template>
<script>
import grandSon from "./grandSon "
export default {
name: "Son",
components: { grandSon },
data () {
return {
title: '子组件'
}
},
};
</script>
//孙组件中使用inject注入
<template>
<div>
<p>message:{{ message }}</p>
</div>
</template>
<script>
export default {
name: "GrandSon",
inject: [ "message" ],
data () {
return {
title: '孙组件'
}
},
methods: { ... }
};
</script>
6. Vuex 适用于父子 隔代 兄弟组件通信
略…