UNPKG

@shuzhong/vue-event-bus

Version:
135 lines (108 loc) 4.12 kB
import Vue, { VueConstructor } from 'vue' declare module 'vue/types/vue' { export interface Vue { $busOn(evTag: string | string[], evFunc: Function): void $busOnce(evTag: string | string[], evFunc: Function): void $busOff(evTag: string | string[], evFunc?: Function): void $busFire(evTag: string | string[], ...args: any[]): void } } type VueEventBusOptions = { events?: string[] strict?: boolean } type EventStoreProp = { [evTag: string]: { evFunc: Function once: boolean self: Vue /* store this for busFire */ }[] } type CompEventStoreProp = { [uid: number]: { [evTag: string]: Function[] } } function VueEventBus(Vue: VueConstructor, { events = [], strict = false }: VueEventBusOptions = {}) { let version = Number((Vue as any).version.split('.')[0]) if(version < 2) { throw new Error('[vue-event-bus] only support vue 2+ ') return } let eventStore: EventStoreProp = {} // Store event use vue._uid -> evTag -> evFunc[], for auto busOff before destory let compEventStore: CompEventStoreProp = {} let validateEvent = function(evTags: string[]) { // when strict = false, stop check if(!strict) { return } for(let evTag of evTags) { if(events.indexOf(evTag) === -1) { throw new Error(`Wrong event ${evTag} in strict mode`) } } } let busAdd = function(this: Vue, evTags: string | string[], evFunc: Function, once = false) { if(typeof evTags === 'string') { evTags = [evTags] } validateEvent(evTags) let uid: number = (this as any)._uid if(!compEventStore[uid]) { compEventStore[uid] = {} } for(let evTag of evTags) { if(!eventStore[evTag]) { eventStore[evTag] = [] } if(!compEventStore[uid][evTag]) { compEventStore[uid][evTag] = [] } eventStore[evTag].push({ evFunc, once, self: this }) compEventStore[uid][evTag].push(evFunc) } } let busOn = function(this: Vue, evTags: string | string[], evFunc: Function) { busAdd.call(this, evTags, evFunc, false) } let busOnce = function(this: Vue, evTags: string | string[], evFunc: Function) { busAdd.call(this, evTags, evFunc, true) } let busOff = function(evTags: string | string[], evFunc?: Function) { if(typeof evTags === 'string') { evTags = [evTags] } validateEvent(evTags) for(let evTag of evTags) { if(!eventStore[evTag] || !evFunc) { eventStore[evTag] = [] continue } eventStore[evTag] = eventStore[evTag].filter(evPart => evPart.evFunc !== evFunc) } } let busFire = function(evTags: string | string[], ...args: any[]) { if(typeof evTags === 'string') { evTags = [evTags] } validateEvent(evTags) for(let evTag of evTags) { if(!eventStore[evTag]) { continue } /* 当在触发事件的函数中添加新的监听函数,该添加的函数将在下一次事件时才触发 */ let tempQueue = eventStore[evTag].slice(0) eventStore[evTag] = eventStore[evTag].filter(evPart => !evPart.once) for(let evPart of tempQueue) { !!evPart.evFunc && evPart.evFunc.apply(evPart.self, args) } } } Vue.mixin({ methods: { $busOn: busOn, $busOnce: busOnce, $busOff: busOff, $busFire: busFire }, beforeDestroy() { let uid: number = (this as any)._uid if(!compEventStore[uid]) { return } for(let evTag in compEventStore[uid]) { for(let evFunc of compEventStore[uid][evTag]) { busOff(evTag, evFunc) } } compEventStore[uid] = {} } }) } /* if(typeof window !== 'undefined' && !!(window as any).Vue) { * (window as any).Vue.use(VueEventBus) * } */ export default VueEventBus