Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Vue】Vue中的事件机制🧀 #54

Open
Easay opened this issue May 4, 2021 · 0 comments
Open

【Vue】Vue中的事件机制🧀 #54

Easay opened this issue May 4, 2021 · 0 comments
Labels

Comments

@Easay
Copy link
Owner

Easay commented May 4, 2021

Vue事件机制本质上是一个发布-订阅模式的实现。在注册事件时,将回调函数收集起来,在触发事件时将收集起来的事件依次调用即可。

在执行new Vue时,Vue会执行this._init方法进行一系列初始化操作,其中会在vue实例上创建一个_events属性,用来存储事件。

class Vue{
    constructor(){
        this._events = Object.create(null); //创建空对象,用来存储事件
    }
}

$on实例方法的原理:

$on(event, fn){
    if(Array.isArray(event)){
        for(let i=0,l=event.length;i<l;i++){
            this.$on(event[i],fn);
        }
    }else{
        (this._events[event] || (this._events[event]=[])).push(fn);
    }
    return this;
}

如果event是数组,则递归对每一项调用$on,使回调可以被注册到数组中每项事件名所指定的事件列表中。当不是数组时,就向对应的事件列表中注册回调。

$off实例方法的原理:
用法:移除自定义的事件监听器

  • 如果没有提供参数,则移除所有事件监听器;
  • 如果只提供了事件,则移除该事件所有的监听器;
  • 如果同时提供了事件与回调,则只移除这个回调的监听器。
$off(event,fn){
    //如果没有提供参数
    if(!arguments.length){
        this._events = Object.create(null);
        return this;
    }
    // return this;
    // 如果event支持数组
    if(Array.isArray(event)){
        for(let i=0,l=event.length;i<l;i++){
            this.$off(event[i],fn);
        }
        return this;
    }
    /**
     * 先判断该事件有没有被监听,如果没有则直接退出;然后判断是否只有一个参数,如果是则移除事件。
     */
    const cbs = this._events[event];
    if(!cbs){
        return this;
    }
    // 移除对应事件的所有监听器
    if(arguments.length==1){
        this._events[event] = null;
        return this;
    }
    /**
     * 如果同时提供了事件和回调,则只移除这个回调的监听器。
     */
    if(fn){
        const cbs = this._events[event];
       // let cb;
        let i = cbs.length;
        while(i--){
            if(cbs[i]==fn || cbs[i].fn==fn){
                cbs.splice(i,1);
                break;
            }
        }
    }
    return this;
}

$once实例方法实现原理:
监听一个方法,但只触发一次。所以实现思路是:在$once中调用$on来监听自定义事件,当事件触发后会执行拦截器,将监听器从事件列表中移除。

$once(event,fn){
    function on(){
        this.$off(event,on);
        fn.apply(this,arguments);
    }
    on.fn = fn;
    this.$on(event,on);
    return this;
}

$emit实例方法实现原理:
触发当前实例上的事件,实现思路是:使用事件名从vm._events中取出对应的事件监听器回调函数列表,然后依次执行列表中的监听器回调并将参数传递给监听器回调。

$emit(event){
    let cbs = this._events[event];
    if(cbs){
       const args = [].slice.call(arguments,1); //将类数组转换成数组,并取除第一个参数以外的所有参数
        for(let i=0,l=cbs.length;i<l;i++){
            try{
                cbs[i].apply(this,args);
            }catch(e){
                handleError(e,this,`event handler for "${event}"`);
            }
        }
    }
    return this;
}
@Easay Easay added the Vue label May 4, 2021
@Easay Easay changed the title 【Vue】Vue中的事件机制 【Vue】Vue中的事件机制🧀 May 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant