资讯专栏INFORMATION COLUMN

【Vue原理】Event - 源码版 之 绑定组件自定义事件

amuqiao / 2245人阅读

摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之绑定组件自定义事件组件

写文章不容易,点个赞呗兄弟
专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧
研究基于 Vue版本 【2.5.17】

如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧

【Vue原理】Event - 源码版 之 绑定组件自定义事件

组件自定义事件其实是我最感兴趣的,我当时花了好多时间去探索的哈哈哈,探索完了之后,发现很简单的,可以先看下白话版了解下

【Vue原理】Event - 白话版

我当时脑海中就几个问题,我很想弄懂啊

1、父给子绑定的事件,存放在父组件还是子组件?

2、父给子绑定自定义事件,子组件为什么可以触发?

3、子组件触发事件后,是怎么调用绑定的 父组件的方法的?

看看当时做的笔记时间,已经过了好久了啊

笔记看着很混乱,所以下定决心写文章,写得详详细细的,然自己一眼就明白,而且怕以后自己忘记

首先肯定是为自己服务的,只是顺便分享给大家,能帮到别人少走弯路而已哈哈哈

好的,不多说了,马上进入主题~~看完文章的欢迎到下面投票啊啊啊啊

怎么解析

同样,一个给组件绑定自定义事件的模板

然后template 解析成下面的渲染函数

渲染函数执行,生成这样的组件外壳VNode

还可以打印组件实例看一下

你可以看到,绑定的自定义事件,存在了 组件外壳VNode的 componentOptions.listeners 中

等下!

渲染函数中,明明把事件解析放在 on 的啊,怎么到 listeners了

这里记录一下哈

当 _c("test") 执行的时候,因为是组件,所以内部会特别调用 createComponent 去生成组件的VNode

而这个VNode 是外壳VNode

下面的源码中可以很清楚的看到

1、把 on 赋值给了 listeners

2、listeners 传给了 VNode 构造函数,保存到了 vnode.componentOptions

function createComponent(
    Ctor, data, context, 
    children, tag
) {    

    var listeners = data.on;

    data.on = data.nativeOn;    

    var vnode = new VNode(

        tag, // 组件名字
        data, undefined, undefined, 
        undefined, context,    
        // 下面这个对象就存在 vnode.componentOptions
        {            
            listeners: listeners,
        }
    );    

    return vnode

}
function VNode(
    tag, data, children, text, 
    elm, context, componentOptions 

) {  
    this.componentOptions = componentOptions;

};

想了解多一点Vnode可以看 VNode - 源码版

想了解 component 流程的,可以看 Component - 白话版

所以第一个问题得到答案,父给子绑定的事件,存放在子组件中!

怎么绑定

好的,模板上的事件已经被解析并保存好了

接下来,就轮到 事件的注册 showtime

这个事情,发生在创建组件实例的时候

如果你要问,具体是怎么到了创建实例这里的话,你可以看下面两篇文章,不过看你有没有这个耐心了(学习的事,能不要耐心吗)

Component - 源码版 之 创建组件VNode

Component - 源码版 之 挂载组件DOM

要不就看白话版吧

Component - 白话版

1、初始化实例

组件实例初始化会调用 Vue.prototype._init 没错了

然后 _init 会调用一个 initEvents 的东东去进行初始化事件对象,如下

Vue.prototype._init = function(options) {  

    // 增加组件选项,详情往下看
    initInternalComponent(vm,options);

    initEvents(vm);    

    ....处理选项数据

}

initEvents:没错就是我!

2、初始化事件对象

initEvent 这个函数做了什么事情呢?

1、给实例上添加一个 _event 对象,用于保存自定义事件

2、获取到 父组件给 子组件绑定的自定义事件(不懂就接着往下看)

3、调用 updateComponentListeners 开始注册

function initEvents(vm) {

    vm._events = Object.create(null);    

    var listeners = vm.$options._parentListeners;    

    if (listeners) {

        updateComponentListeners(vm, listeners);
    }
}

有个疑惑

_parentListeners 保存的是什么东西?父组件给子组件的事件?

百思不得其解,诶,看到_init 中有一句代码调用initInternalComponent,也许就是这个函数搞的鬼,我们来看下

3、初始化组件信息
function initInternalComponent(vm, options) { 

    .....保存节点等信息
    
    // _parentVnode 是外壳节点
    var parentVnode = options._parentVnode; 
    
    // 保存父组件给子组件关联的数据
    var vcp= parentVnode.componentOptions;

    vm.$options._parentListeners =vcp.listeners;   

    ....保存渲染函数

}

这个函数的作用是初始化一些组件的信息,包括转移一些数据

哦~~原来就是通过这个函数偷偷摸摸转移了 listeners 到了 vm.$option._parentListeners

前面说过【父给子绑定的事件】解析存放在 外壳节点vnode.componentOptions.listeners 中(不明白可以翻到上面的<怎么解析>部分),然后转移的就是这个 listeners

解决这个疑惑了,好的,我们接着来走 initEvent 剩下的流程把~~

来看下 updateComponentListeners

4、注册事件
function updateComponentListeners(
    vm, listeners, oldListeners

) {

    var name, cur, old;    

    for (name in listeners) {

        cur = listeners[name];

        old = oldListeners[name];   

        // 没有旧事件,就直接添加新事件

        if (typeof old === "undefined") {
            vm.$on(name, cur);
        }      

        // 新事件和旧事件不一样,替换旧事件
        else if (cur !== old) {
            on[name] = cur;
        }
    }    

    // 移除旧事件
    for (name in oldListeners) {        

        if (typeof listeners[name] === "undefined") {

            vm.$off(name, oldOn[name]);
        }
    }
}

就是从他这里开始注册事件的

似乎没什么好说的,注意一点

绑定和解绑事件,是直接调用 Vue 的自定义事件方法 $on 和 $off ,大家是不是很熟悉???

没错,在这篇文章中说过

【Vue原理】Event - 源码版 之 自定义事件

这就解释我们开篇第二个问题了!!!!

为什么我给子组件绑定自定义事件,可以在子组件像下面这样触发?

this.$emit("test")

因为 组件绑定的自定义事件 和 Vue 的自定义事件

两种事件都是使用同一种方法注册的,所以都存在同样一个事件对象 【vm._events】 中,是一样操作的流程

就是这样的

可以看到组件实例上的 _events

并且知道了第三个问题,怎么调用到父组件的方法?

因为给子组件注册事件的时候,直接存放父组件的回调,所以触发事件会调用到父组件的方法

然后你还可以问出一个问题!

为什么子组件触发事件之后,调用父组件的方法,而父组件的方法上下文对象还是父组件

哈哈,因为 methods 方法已经使用 bind 绑定啦,上下文对象固定了为父组件实例的,所以不管谁调用,怎么调用,都是父组件

详情可以看这里,

Methods - 源码版

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/105513.html

相关文章

  • Vue原理】Compile - 源码 generate 拼接绑定事件

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之拼接绑定的事件今天我们 写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究...

    OnlyMyRailgun 评论0 收藏0
  • Vue原理Event - 白话

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理白话版事件是我最感兴趣的东西之 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    kumfo 评论0 收藏0
  • Vue原理Event - 源码 绑定组件DOM事件

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之绑定组件事件上一篇已经 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    Mr_zhang 评论0 收藏0
  • Vue原理Event - 源码 定义事件

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之自定义事件的自定义事件 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    yunhao 评论0 收藏0
  • Vue原理Event - 源码 绑定标签DOM事件

    摘要:写文章不容易,点个赞呗兄弟专注源码分享,文章分为白话版和源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于版本如果你觉得排版难看,请点击下面链接或者拉到下面关注公众号也可以吧原理源码版之绑定标签事件这里的绑定 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于...

    phoenixsky 评论0 收藏0

发表评论

0条评论

amuqiao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<