Vue $on 和 $emit

7,813 阅读1分钟

$on

$on 是用来在监听(注册)自定义事件的。

使用方法:

vm.$on(event, callback)

参数:

  1. event {string | Array} (自定义事件的名称,可以使用数组的方式复数注册。数组方式必须在2.2.0+中才支持)
  2. callback {Function} (自定义事件触发后,所执行的方法、函数)

示例:

vm.$on('myEvent', function(data) {
    console.log(data);
});

源码:

var hookRE = /^hook:/;

Vue.prototype.$on = function(evert, fn) {
    var vm = this; // this 就是 Vue 实例
    
    // 判断 event 是否是数组
    if(Array.isArray(event)) { // 当 event 是数组的时候,对数组进行循环,分次将事件注册。
        for(var i = 0, l = event.length; i < l; i++) {
            vm.$on(event[i], fn);
        }
    } else { 
        // 当event不是数组的时候,判断event是否注册过。
        // 1、注册过,直接将方法push进对应的数组中。
        // 2、没有注册过先在vm._events里面注册一个对应的数组,然后再把方法push进数组中。
        // 这里其实就意味着,一个自定义事件,其实可以对应着多个方法,方法的执行顺序,就是添加顺序。
        
        (vm._events[event] || (vm._events[event] = [])).push(fn);
        
        if(hookRE.test(event)) {
            vm._hasHookEvent = true;
        }
    }
    
    return vm;
}

$emit

$emit 是手动触发当前实例上的一个指定事件。

使用方法:

vm.$emit(eventName, [...args])

参数:

  1. eventName {string} (需要触发的事件名称)
  2. [...args] (传递的参数,多个参数用数组,单个参数就可以直接用参数本身的格式)

示例:

vm.$emit('myEvent', 'happy');

源码:

Vue.prototype.$emit = function(event) {
    var vm = this;
    
    {
        // 这里是将eventName变换为小写,并做一些检查
        var lowerCaseEvent = event.toLowerCase();
        
        if(lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
            tip(
                "Event \"" + lowerCaseEvent + "\" is emitted in component " +
                (formatComponentName(vm)) + " but the handler is registered for \"" + event + "\". " +
                "Note that HTML attributes are case-insensitive and you cannot use " +
                "v-on to listen to camelCase events when using in-DOM templates. " +
                "You should probably use \"" + (hyphenate(event)) + "\" instead of \"" + event + "\"."
          );
        }
    }
    
    // 获取该事件下的方法、函数
    var cbs = vm._events[event];
    
    // 判断cbs是否有值,是否为真
    if(cbs) { // 当cbs为真的时候。
        
        // 判断cbs是否大于一,如果大于一就确保cbs是一个数组,如果不大于一,就直接返回cbs
        cbs = cbs.length > 1 ? toArray(cbs) : cbs;
        
        // 获取传入的参数,大体就是,把arguments转换成数组,并且获取它下标为1的值
        var args = toArray(arguments, 1);
    
        var info = "event handler for \"" + event + "\"";
        
        // 遍历cbs
        for(var i = 0, l = cbs.length; i < l; i++) {
            // 通过invokeWithErrorHandling方法,来安全的执行cbs[i],大体就是try catch, 防止方法出现异常的时候不会中断程序的执行。
            invokeWithErrorHandling(cbs[i], vm, args, vm, info);
        }
    }
    
    // 这里当cbs为假的时候会直接return vm什么都不会操作
    return vm;
}