vue源码解读--event(原生事件-invoke)

目录导航

本节沿用上一节代码

经过parse分析,我们知道了vue在匹配到结束标签时会调用parseEndTag对ast元素节点进行加工,并最终生成一个带events标记的ast节点;在codegen阶段,则会调用gendata执行addHandler对事件进行处理,并生成on对象来对事件进行描述,每一个key都对应一个匿名函数,并将我们定义的函数作为返回值返回,因为在返回我们自己定义的函数之前vue还要对event对象、自定义修饰符进行处理,每一个自定义的修饰符都对应着一段特别的代码,如.stop修饰符最终对象的匿名函数将如下

            function($event){

                $event.stopPropagation()

                return onConsole($event)

            }

这小节,我们将分析在运行时阶段,这些函数将如何被调用(invoke)

我们知道path函数是经过createPatchFunction返回的,它接收一个对象,nodeOps是与dom操作相关的api

modules则是处理模块相关的api

可以看到,在生成path函数的过程中已经将事件相关的api传入了,那么我们看下createPatchFunction

    可以看到,首当其冲的向cbs中保存了一些值,值则来自于hooks

    结合我们事件模块导出的结果,我们推断出,cbs中缓存了事件的create和update函数

    而它的调用则是在子元素被创建但未被插入时,即

    即

    在对cbs的遍历过程中将执行到事件模块导出的函数,即updateDOMListeners

    调用updateListeners

    框红的位置,是对应我们第一次patch,那时是没有旧节点的。那么理所应当的,框黄的位置,则对应组件更新阶段的patch

    首先看框红的内容,调用createFnInvoker,传入我们定义的回调函数

        可以看到,框红的位置将我们传入的回调函数挂载到了invoker函数上并返回,因此on.click=invoker,而involer中又调用了invokeWithErrorHandling

        显然,在这里对函数进行了调用。那么现在关键的就是什么时候调用了invoker函数(a)

        返回updateListeners框红的位置,向下判断是否定义了once修饰符,如果定义了则执行createOnceHandler,即remove函数

        多么熟悉的api啊,也就是说once之所以只执行一次,是因为执行后就被释放掉了

        返回updateListeners框红的位置,调用add函数

        框红一的位置在invoker调用之前加了一些判断代码

        框红二的位置则调用原生dom api绑定dom事件

    此时,当点击时便会调用invoker函数了(a),在invoker中将会对我们定义的函数进行遍历,并在invokeWithErrorHandling进行调用,这将最终调用到我们代码中定义的onConsole函数

返回updateListeners框黄的位置,当第二次组件更新阶段,旧vnode有值,故将走进判断。可以看到这里只是简单的将cur挂载到了old.fns上。而cur和old都是获取的vnode上的on属性,我们知道,在ast节点创建过程中会将事件描述到events上,在代码生成阶段会将events转化为on属性,这一过程是只执行一次,因为我们不可能将我们写的代码进行非手动删除。那么在add阶段,则针对不同的事件类型在元素上添加过回调,故再次render期间,元素的回调仍是存在的。又由于回调执行的实际上是fns,故我们只需要替换fns的引用即可(b)

那么,组件更新过程中做了哪些事情呢,为什么能再次走到(b)呢?

我们知道,组件更新会再次patch,并调用patchVnode,并在该函数中再次遍历cbs

    由于cbs中保存了事件处理模块的api,故和第一次一样会执行到updateDOMListeners,只不过这次的oldvnode是有值的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容