子父组件通信
props
父组件将一个函数作为 props 传递给子组件,子组件接收后调用该函数将想要传递的数据以实参的形式传递。
<!-- 准备一个容器 --><div id="root">爸爸的小金库有{{money}}元 <br><Son :give="addMoney"></Son></div><template id="son"><div><button @click="giveMoney">给爸爸发{{HongBao}}红包</button></div></template><script type="text/javascript">const Son = Vue.extend({template: '#son',data() {return {HongBao: 888,}},props: ['give'],methods: {giveMoney() {this.give(this.HongBao);}}})// 创建vue实例new Vue({el: '#root',data: {money: 1000,},methods: {addMoney(money) {this.money += money;}},components: {Son,}})</script>
自定义事件
1. 一种组件间的通信方式,适用于 子组件 ===> 父组件2. 使用场景:A是父组件,B是子组件,B想给A传递数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。3. 绑定自定义事件:<br /> 1. 第一种方式:在父组件中` <Son @=myEventName = "fn" / >`<br /> 2. 第二种方式:在父组件中:
<Son ref = "sonCV" />....mounted(){this.$refs.sonCV.$on('myEventName',this.fn);}
3. 若想让自定义事件只触发一次,可以使用`once` 修饰符,或者使用 `$once` 方法。4. 触发自定义事件:子组件中 `this.$emit('myEventName', ...数据)`5. 解除自定义事件 `this.$off('myEventName')`6. 组件上可以绑定原生DOM事件,需要使用 native 修饰符。这是因为组件上的事件会被认为是自定义事件 如 `<Son @click='fn' />` 会以为是名为click的自定义事件。7. 注意:通过 this.$refs.xxx.$on('myEventName', fn) 绑定自定义事件时,回调要么配置在 methods 中,要么使用箭头函数,否则this指向会出现问题!!
<!-- 准备一个容器 --><div id="root">爸爸的小金库有{{money}}元 <br><!-- 方法一 -->儿子1<Son @give-hongbao="addMoney"></Son><!-- 方法二 -->儿子2<Son ref="sonRef"></Son></div><template id="son"><div><button @click="giveMoney">给爸爸发{{HongBao}}红包</button><button @click="relieve">解除自定义事件</button></div></template><script type="text/javascript">const Son = Vue.extend({template: '#son',data() {return {HongBao: 888,}},methods: {giveMoney() {console.log('我要触发自定义事件');this.$emit('give-hongbao', this.HongBao);},relieve() {// this.$off(); // 解除所有自定义事件// this.$off(['give-hongbao']); // 解除多个自定义事件this.$off('give-hongbao'); // 解除一个自定义事件console.error('解除自定义事件');}}})// 创建vue实例new Vue({el: '#root',data: {money: 1000,},// 方法一:使用methodsmethods: {addMoney(sonHongBao) {console.log('%c 自定义事件被触发了 ', 'background-color:green;');this.money += sonHongBao;},},// 方法二:使用refmounted() {this.$refs.sonRef.$on('give-hongbao', (sonHongbao) => {this.money += sonHongbao;})},components: {Son,}})</script>
兄弟组件通信

当我们要把 Header 组件中的数据 传递到 List 组件中时,我们可以使用 全局事件总线、消息订阅与发布、VUEX 等。
但是我们此处要学的是最初级的做法。状态上升,使下组件无状态化。
人话就是:
因为 Header 和 LIst 组件现在无法正常沟通,我们就把他们的数据给到共同的父组件 APP 。
APP通过创建一个方法 methods,把方法通过 props 传递给子组件 Header,Header 通过调用该方法,获取父组件中的参数。
隔代组件通信 $attrs
思路:把爷爷组件需要传递的数据通过 props 给到 Father 组件,Father 不声明 props 进行接收,而是给 Father 组件内部的 Grandson 组件添加v-bind="$attrs",然后 Grandson 组件就可以通过 this.$attrs.propsName。
关于 vm.$attrs vue官网的介绍:
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建高级别的组件时非常有用。
<div id="root"><Father :toGrandsonHongbao="HongBao"></Father><button @click="giveMoney">爷爷给孙子发{{HongBao}}红包</button></div><!-- 父亲组件 --><template id="father"><div><Grandson v-bind="$attrs"></Grandson></div></template><!-- 孙子组件 --><template id="grandson"><div>孙子有{{money}}元,和爷爷给的{{$attrs.tograndsonhongbao}}</div></template>
const Grandson = Vue.extend({template: '#grandson',// // 默认情况下父作用域的不被认作 props 的 attribute 绑定 (attribute bindings) 将会“回退”且作为普通的 HTML attribute 应用在子组件的根元素上。当撰写包裹一个目标元素或另一个组件的组件时,这可能不会总是符合预期行为。通过设置 inheritAttrs 到 false,这些默认行为将会被去掉inheritAttrs: false,data() {return {money: 10,}},})const Father = Vue.extend({template: '#father',components: {Grandson,},})// 创建vue实例new Vue({el: '#root',data: {HongBao: 0,},methods: {giveMoney() {this.HongBao = 1000;}},components: {Father,},})
provide/inject
Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。
provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
// 父级组件提供 'foo'var Provider = {provide: {foo: 'bar'},// ...}// 子组件注入 'foo'var Child = {inject: ['foo'],created () {console.log(this.foo) // => "bar"}// ...}
全局事件总线 GlobalEventBus
EventBus 是一种组件间的通信方式,适用于任意组件间通信,是一种 发布——订阅的设计模式。

全局事件总线操作流程
new Vue({...beforeCreate(){Vue.prototype.$bus = this;},})
this.$bus.$on('myEvent', (data) => { ... });
this.$bus.$emit('myEvent', this.data);
由于自定义事件是绑定给 $bus 身上的,事件不会随着组件的销毁而自动解绑,因此需要在绑定事件的组件上进行解绑
this.$bus.off('myEvent');
为什么可行?
- Vue 原型对象上包含事件处理的方法
$on(eventName, listener) 绑定自定义事件监听$emit(eventName, data) 分发自定义事件$off(eventName) 解绑自定义事件监听$once(eventName, listener) 绑定自定义事件监听,但只能处理一次
所有组件实例对象的原型对象的隐式原型属性 指向 Vue 的原型对象
VueComponent.prototype.proto === Vue.prototype
所有组件实例对象都能访问到Vue原型对象上的属性和方法。
Vue.prototype.bus = new Vue(),所有组件实例对象都可以访问到 bus 这个属性。
<!-- 准备一个容器 --><div id="root">爸爸的小金库有{{money}}元 <br><eldest-son></eldest-son><youngest-son></youngest-son></div><template id="eldestSon"><div><button @click="giveMoney">给弟弟发{{HongBao}}红包</button></div></template><template id="youngestSon"><div>小儿子有{{money}}元</div></template><script type="text/javascript">const eldestSon = Vue.extend({template: '#eldestSon',data() {return {HongBao: 200,}},methods: {giveMoney() {this.$EventBus.$emit('give-youngestSon', this.HongBao);}},})const youngestSon = Vue.extend({template: '#youngestSon',data() {return {money: 100,}},mounted() {this.$EventBus.$on('give-youngestSon', (money) => {this.money += money;})},beforeDestroy() {this.$EventBus.$off('give-youngestSon');},})// 创建vue实例const vm = new Vue({el: '#root',data: {money: 1000,},beforeCreate() {Vue.prototype.$EventBus = this; // 安装全局事件总线,所有的组件对象都可以看到 $EventBus 这个属性// Vue.prototype.$EventBus = new Vue(); // 安装全局事件总线,所有的组件对象都可以看到 $EventBus 这个属性},components: {'eldest-son': eldestSon,'youngest-son': youngestSon,},mounted() {},})</script>
消息订阅与发布 pubsub
一种组件间通信的方式,适用于任意组件间通信。
基于 pubsub-js 实现
安装:pubsub-js
npm install —save pubsub-js
引入:PubSub
接收消息和发送消息的组件都需要引入这个库!!
import PubSub from 'pubsub-js';console.log(PubSub);

接收数据的组件需要订阅消息
mounted() {// 挂载完毕,订阅一个名为myMsg消息,类似js中的定时器会返回一个id,用这个id取消订阅。this.pubId = PubSub.subscribe('myMsg', (msgName, data) => {......// msgName是消息名 即myMsg// data 是传递来的数据})},
发送数据的组件需要发布消息
PubSub.publish('myMsg', this.data);
接收数据的组件销毁后需要取消订阅
beforeDestroy() { // 组件销毁前阶段 取消订阅 pubId 这个消息PubSub.unsubscribe(this.pubId);},
- 使用消息订阅与发布实现兄弟组件传参(大儿子给小儿子包红包) ```html <!DOCTYPE html>
```javascriptconsole.log(PubSub);const eldestSon = Vue.extend({template: '#eldestSon',data() {return {HongBao: 200,}},methods: {giveMoney() {// 发布消息PubSub.publish('myMsg', this.HongBao);}},})const youngestSon = Vue.extend({template: '#youngestSon',data() {return {money: 100,}},mounted() {// 挂载完毕,订阅一个名为myMsg消息,类似js中的定时器会返回一个id,用这个id取消订阅。this.pubId = PubSub.subscribe('myMsg', (msgName, data) => {console.log('youngestSon订阅的myMsg被发布了', msgName, data);this.money += data;})},beforeDestroy() {PubSub.unsubscribe(this.pubId);},})// 创建vue实例const vm = new Vue({el: '#root',data: {money: 1000,},components: {'eldest-son': eldestSon,'youngest-son': youngestSon,},})
