源码

    1. // $on 的实现逻辑
    2. Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
    3. const vm: Component = this
    4. if (Array.isArray(event)) {
    5. for (let i = 0, l = event.length; i < l; i++) {
    6. vm.$on(event[i], fn)
    7. }
    8. } else {
    9. (vm._events[event] || (vm._events[event] = [])).push(fn)
    10. }
    11. return vm
    12. }
    13. // $emit 的实现逻辑
    14. Vue.prototype.$emit = function (event: string): Component {
    15. const vm: Component = this
    16. let cbs = vm._events[event]
    17. if (cbs) {
    18. cbs = cbs.length > 1 ? toArray(cbs) : cbs
    19. const args = toArray(arguments, 1)
    20. const info = `event handler for "${event}"`
    21. for (let i = 0, l = cbs.length; i < l; i++) {
    22. invokeWithErrorHandling(cbs[i], vm, args, vm, info)
    23. }
    24. }
    25. return vm
    26. }
    27. // invokeWithErrorHandling 的实现逻辑
    28. export function invokeWithErrorHandling (
    29. handler: Function,
    30. context: any,
    31. args: null | any[],
    32. vm: any,
    33. info: string
    34. ) {
    35. let res
    36. try {
    37. res = args ? handler.apply(context, args) : handler.call(context)
    38. } catch (e) {
    39. handleError(e, vm, info)
    40. }
    41. return res
    42. }

    分析

    1. 首先我们都了解vue的数据相应是依赖于“观察-订阅”模式,$on、$emit也不例外;
    2. $on用来收集所有的事件依赖,他会将传入的参数event和fn作为key和value的形式存到vm._events这个事件集合里,就像这样vm._events[event]=[fn];
    3. 而$emit是用来触发事件的,他会根据传入的event在vm_events中找到对应的事件并执行invokeWithErrorHandling(cbs[i], vm, args, vm, info)
    4. 最后我们看invokeWithErrorHandling方法可以发现,他是通过handler.apply(context, args)和handler.call(context)的形式执行对应的方法

    接着就可以根据 $on、$emit的实现方式来写一个eventBus。