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