vue组件通信方式是个老生常谈的话题了,最全面的莫过于 vuex
,最简单的就是父子组件 props
传值,今天我们重点来说说经常提到的 bus
模式。
bus使用
- 使用Vue创建新实例
Vue.prototype.$bus = new Vue(); 复制代码
$bus
实际就是个 Vue
实例对象
- 定义事件监听函数
// A.vue created() { this.$bus.$on('setName', (name) => { console.log('receive:' + name) }) } 复制代码
- 触发事件
// B.vue mounted() { this.$bus.$emit('setName', 'Job') } 复制代码
- 移除事件
// A.vue destroyed() { this.$bus.$ff('setName') } 复制代码
我们在这边只传递了一个事件名参数 setName
,这时会移除所有的 setName
监听函数,在实际使用的时候,我们一般会添加第二个参数来指定移除的监听函数
this.$bus.$ff('setName', fn); // fn的指针地址需要和创建($on)添加的函数相同,这点和removeEventListener是一致的 复制代码
bus使用注意事项
bus模式实际是非常简单的,简单加上日常并不一定需要去使用,以至于我们经常忘记如何使用它。使用的时候有几个需要注意的点
- 在组件中使用
this.$bus
之前要先往原型上注册该实例Vue.prototype.$bus = new Vue()
- 在触发事件
this.$bus.$emit(xxx)
之前应该先定义监听函数this.$bus.$on(xxx, fn)
- 在组件销毁的时候,如有必要是需要移除事件的
this.$bus.$off(xxx, fn)
,不然会多次重复监听
bus模式的原理
知道 订阅发布模式
的一眼就能看出 bus
其实就是一个 订阅发布
的实现。通过 $on
添加订阅,通过 $emit
触发通知广播。关于订阅发布模式可以看看浅谈订阅发布实现vue
所以说,我们的 bus
模式实际是利用了 vue
中的一个 订阅发布
实现,我们通过实例方法 $on
,$emit
,$off
来触发 vue
是事件订阅中心。
我们接着来看看其源码部分
- $on
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component { const vm: Component = this // 可以使用数组同时添加多个订阅 if (Array.isArray(event)) { for (let i = 0, l = event.length; i < l; i++) { vm.$on(event[i], fn) } } else { // 订阅:往事件中心vm._events添加事件回调函数fn (vm._events[event] || (vm._events[event] = [])).push(fn) // ... } return vm } 复制代码
- $emit
Vue.prototype.$emit = function (event: string): Component { const vm: Component = this // 先取事件中心的event类型回调函数 let cbs = vm._events[event] if (cbs) { cbs = cbs.length > 1 ? toArray(cbs) : cbs const args = toArray(arguments, 1) const info = `event handler for "${event}"` // 依次触发事件回调函数fn for (let i = 0, l = cbs.length; i < l; i++) { invokeWithErrorHandling(cbs[i], vm, args, vm, info) } } return vm } 复制代码
- $off
Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component { const vm: Component = this // 没有event参数将移除全部 if (!arguments.length) { vm._events = Object.create(null) return vm } // 可移除事件数组 if (Array.isArray(event)) { for (let i = 0, l = event.length; i < l; i++) { vm.$off(event[i], fn) } return vm } // 没有回调函数则直接退出 const cbs = vm._events[event] if (!cbs) { return vm } // 没有fn参数将移除所有event类型回调 if (!fn) { vm._events[event] = null return vm } // 移除特定事件 // 可以发现只会移除第一个符合条件的函数 let cb let i = cbs.length while (i--) { cb = cbs[i] if (cb === fn || cb.fn === fn) { cbs.splice(i, 1) break } } return vm } 复制代码
总结
我们今天分析了bus模式的组件通信方式及其实现原理,整体比较简单 good good staduy day day up