EventBus
许多现代JavaScript框架和库的核心概念是能够将数据和UI封装在模块化、可重用的组件中。这对于开发人员可以在开发整个应用程序时避免使用编写大量重复的代码。虽然这样做非常有用,但也涉及到组件之间的数据通讯。对于vue来说,存在着父子组件、兄弟组件、跨级组件之间的通信问题。在Vue中组件之间的通讯有一定的原则。
父子组件通信原则:
为了提高组件的独立性与重用性,父组件会通过props向下传数据给子组件,当子组件有事情要告诉父组件时会通过$emit事件告诉父组件。如此确保每个组件都是独立在相对隔离的环境中运行,可以大幅提高组件的维护性。
EventBus
简单介绍
EventBus又称为事件总线。在Vue中可以使用EventBus来作为沟通桥梁的概念,就像是所有组件共用相同的事件中心,可以向该中心注册发送事件或接收事件,所有组件都可以上下平行地通知其他组件,但也就是太方便所以若使用不慎,就会造成难以维护的灾难,因此才需要更完善的Vuex作为状态管理中心,将通知的概念上升到共享状态层次。
vue项目中如何使用EventBus?
1.首先创建事件总线并将其导出,以便其它模块可以使用或者监听它
。我们可以通过两种方式来处理。先来看第一种,新创建一个.js文件,比如event-bus.js
:
// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()
你需要做的只是引入 Vue 并导出它的一个实例(在这种情况下,我称它为 EventBus )。实质上它是一个不具备 DOM 的组件,它具有的仅仅只是它实例方法而已,因此它非常的轻便。
另外一种方式,可以直接在项目中的main.js初始化EventBus:
// main.js
Vue.prototype.$EventBus = new Vue()
注意,这种方式初始化的EventBus是一个全局的事件总线。稍后我们会花点时间专门聊一聊全局的事件总线。
- 在组件中加载,并且调用同一个方法,就如你在父子组件中互相传递消息一样。
发送事件:
假设你有两个子组件:DecreaseCount和IncrementCount
,分别在按钮中绑定了decrease()和increment()
方法。这两个方法做的事情很简单,就是数值递减(增)1,以及角度值递减(增)180。在这两个方法中,通过EventBus.$emit(channel: string, callback(payload1,…))
监听decreased(和incremented)
频道。
<!-- DecreaseCount.vue -->
<template>
<button @click="decrease()">-</button>
</template>
<script>
import { EventBus } from "../event-bus.js"; //导入eventBus
export default {
name: "DecreaseCount",
data() {
return {
num: 1,
deg:180
};
},
methods: {
decrease() {
EventBus.$emit("decreased", { //监听decreased事件
num:this.num,
deg:this.deg
});
}
}
};
</script>
<!-- IncrementCount.vue -->
<template>
<button @click="increment()">+</button>
</template>
<script>
import { EventBus } from "../event-bus.js"; //引入eventBus
export default {
name: "IncrementCount",
data() {
return {
num: 1,
deg:180
};
},
methods: {
increment() {
EventBus.$emit("incremented", { //监听incremented事件
num:this.num,
deg:this.deg
});
}
}
};
</script>
上面的示例,在DecreaseCount和IncrementCount
组件中分别发送出了decreased
和incremented
频道。接下来,我们需要在另一个组件中接收这两个事件,保持数据在各组件之间的通讯。
接收事件
在组件App.vue中使用EventBus.$on(channel: string, callback(payload1,…))
监听DecreaseCount和IncrementCount分别发送出的decreased和incremented频道
。
<!-- App.vue -->
<template>
<div id="app">
<div class="container" :style="{transform: 'rotateY(' + degValue + 'deg)'}">
<div class="front">
<div class="increment">
<IncrementCount />
</div>
<div class="show-front">
{{fontCount}}
</div>
<div class="decrement">
<DecreaseCount />
</div>
</div>
<div class="back">
<div class="increment">
<IncrementCount />
</div>
<div class="show-back">
{{backCount}}
</div>
<div class="decrement">
<DecreaseCount />
</div>
</div>
</div>
</div>
</template>
<script>
import IncrementCount from "./components/IncrementCount";
import DecreaseCount from "./components/DecreaseCount";
import { EventBus } from "./event-bus.js"; //同样需要引入 eventBus
export default {
name: "App",
components: {
IncrementCount,
DecreaseCount
},
data() {
return {
degValue:0,
fontCount:0,
backCount:0
};
},
mounted() {
EventBus.$on("incremented", ({num,deg}) => {
this.fontCount += num
this.$nextTick(()=>{
this.backCount += num
this.degValue += deg;
})
});
EventBus.$on("decreased", ({num,deg}) => {
this.fontCount -= num
this.$nextTick(()=>{
this.backCount -= num
this.degValue -= deg;
})
});
}
};
</script>
如果你只想监听一次事件的发生,可以使用 EventBus.$once(channel: string, callback(payload1,…))
移除事件监听者
import { eventBus } from './event-bus.js'
EventBus.$off('decreased', {})
也可以使用 EventBus.$off(‘decreased’)
来移除应用内所有对此事件的监听。或者直接调用 EventBus.$off()
来移除所有事件频道,注意不需要添加任何参数。
上面就是EventBus的使用方式,是不是很简单。上面的示例中我们也看到了,每次使用EventBus时都需要在各组件中引入event-bus.js
。事实上,我们还可以通过别的方式,让事情变得简单一些。那就是创建一个全局的EventBus
。接下来的示例向大家演示如何在Vue项目中创建一个全局的EventBus。
全局EventBus
全局EventBus,虽然在某些示例中不提倡使用,但它是一种非常漂亮且简单的方法,可以跨组件之间共享数据。
它的工作原理是发布/订阅方法,通常称为Pub/Sub。
我们从上图中可以得出以下几点:
- 有一个全局EventBus
- 所有事件都订阅它
- 所有组件也发布到它,订阅组件获得更新
所有组件都能够将事件发布到总线,然后总线由另一个组件订阅,然后订阅它的组件将得到更新.
创建全局EventBus
var EventBus = new Vue();
Object.defineProperties(Vue.prototype, {
$bus: {
get: function () {
return EventBus
}
}
})
这个特定的总线使用两个方法$on和$emit
。一个用于创建发出的事件,它就是$emit
;另一个用于订阅$on
:
我们创建了一个ShowMessage的组件用来显示信息,另外创建一个UpdateMessage的组件,用来更新信息。
在UpdateMessage组件中触发需要的事件。在这个示例中,将触发一个updateMessage事件,这个事件发送了updateMessage的频道:
<!-- UpdateMessage.vue -->
<template>
<div class="form">
<div class="form-control">
<input v-model="message" >
<button @click="updateMessage()">更新消息</button>
</div>
</div>
</template>
<script>
export default {
name: "UpdateMessage",
data() {
return {
message: "这是一条消息"
};
},
methods: {
updateMessage() {
this.$bus.$emit("updateMessage", this.message);//相当于发布事件
}
},
beforeDestroy () {
$this.$bus.$off('updateMessage') //在组件摧毁前移除订阅
}
};
</script>
监听事件:
<!-- ShowMessage.vue -->
<template>
<div class="message">
<h1>{{ message }}</h1>
</div>
</template>
<script>
export default {
name: "ShowMessage",
data() {
return {
message: "我是一条消息"
};
},
created() {
var self = this
this.$bus.$on('updateMessage', function(value) { //订阅事件
self.updateMessage(value);
})
},
methods: {
updateMessage(value) {
this.message = value
}
}
};
</script>
总结:本文主要介绍了在vue中如何利用EventBus快速实现兄弟组件之间的通信。