事件Bus在手 天下我有~
事件Bus是什么 ?
它是一个Vue实例 , 用作一个组件内或者页面内的事件中心总线 , 帮助组件内通信
Vue教程中是有提到 Bus的用法 , 但是因为Vuex的存在 , 它被放在了一个很不起眼的地方 .
$dispatch
和$broadcast
已经被弃用。请使用更多简明清晰的组件间通信和更好的状态管理方案,如:Vuex。
因为基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的过程中会变得越来越脆弱。这种事件方式确实不太好,我们也不希望在以后让开发者们太痛苦。并且$dispatch
和$broadcast
也没有解决兄弟组件间的通信问题。
对于$dispatch
和$broadcast
最简单的升级方式就是:通过使用事件中心,允许组件自由交流,无论组件处于组件树的哪一层。由于 Vue 实例实现了一个事件分发接口,你可以通过实例化一个空的 Vue 实例来实现这个目的。
这些方法的最常见用途之一是父子组件的相互通信。在这些情况下,你可以使用 [v-on
监听子组件上 emit` 并没有什么用。相反,用集中式的事件中间件可以做到简单的升级。这会让组件之间的通信非常顺利,即使是兄弟组件。因为 Vue 通过事件发射器接口执行实例,实际上你可以使用一个空的 Vue 实例。
为什么有Vuex , 但我仍然要推荐用它 看一下使用场景吧
比如这个按钮
点击 展开后
它可以通过点击叉叉关闭 , 这个很简单 , 但是我也实现点击别处自动关闭 可能是点击上栏 , 可能是滑动屏幕 或者其他你所想 .
很明显这是一件一件的事情 .
你可以设置Vuex 并在不同组件中的事件设置这个开关的状态buttonOpenState为
false
但是这个开关并非看到的一个状态那么简单 , 它涉及动画,防抖等 , 可能还需要执行某个开关函数完成这个功能 , 所以我们需要先computed返回这个Vuex中的值作为本地的状态(因为watch无法监测Vuex中的值) , 然后再设置watch来监控它的变化并执行开关函数 .
为了这个开关 , 我们要向Vuex存一个用完就丢的值 , 要专门copmputed返回一个值 , 还要写一个watch来执行函数 , 虽然比一层层传值好了很多但是比较冗杂 .
再比如一个被复用的通知框 , 一个状态是是否显示 , 一个状态是通知的内容 , 这时候Vuex就需要存两个变量 . 显得非常沉迂 .
这个时候事件Bus出场了
它的原理是使用
$emit
, $on
, $off
分别来分发、监听、取消监听事件首先这个
Bus
的Vue实例是独立开项目中组件的在某个页面新建文件
eventHub.js
import Vue from 'vue'
export default new Vue();
在这个页面引入这个Vue实例然后
//eventHub就是刚刚创建的bus实例
methods: {
addTodo: function () {
eventHub.$emit('add-todo', { text: this.newTodoText })
this.newTodoText = ''
}
}
created: function () {
eventHub.$on('add-todo', this.addTodo)
eventHub.$on('delete-todo', this.deleteTodo)
},
// 最好在组件销毁前
// 清除事件监听
beforeDestroy: function () {
eventHub.$off('add-todo', this.addTodo)
eventHub.$off('delete-todo', this.deleteTodo)
},
使用on 发送 , 接受事件 . 这样子就完成了bus的功能
如果你不想每次都引入Bus实例你可以
//1.在main.js中挂载至原型链
Vue.prototype.bus = new Vue()
//2.写在Vuex里 与Vuex的模块对应
const schedule = {
state:{
week:0,
Bus:new Vue(),
},
mutations:{
changeWeek(state,par){
state.week = par;
}
},
}
//3.使用依赖注入 , 一个页面把最上层的页面组件作为Bus ,
//比较推荐这种 , 写法简洁也保证一个页面一个Bus , 而且利用了Vue实例
//页面顶层组件
provide() {
return {
Bus: this,
}
},
//页面内组件
inject:['Bus'],
created() {
this.Bus.$on('dosomething', function(){
...
});
},
beforeDestroy() {
this.Bus.$off('dosomething');
},
实际上Bus是有缺点的 , 在vue-dev-tool 调试时 , 无法知道是哪里发生了事件 ($emit) , 所以虽然它非常简洁 , 他不适合一个所有情景 , 我个人认为它是比较适合当别的组件想改变某个组件内部状态的情况 , 而组件间共享的数据 , 比如
选择星期数 , 有三四处组件需要联动改变 , 这就应该用Vuex了
Bus -> 多组件改一组件
Vuex->多组件用一数据