• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

VUE2/3源码对事件绑定的巧妙处理

武飞扬头像
JetTsang
帮助46

简介

传统的给dom更改绑定事件处理函数,通常都是先remove,再add,而在我最近看Vue源码之后,发现Vue当中对事件绑定的处理非常巧妙。废话不多说,直接上代码。

源码处理流程对比

vue2

首先在vue2源码当中找出对应的处理函数

updateDOMListeners 这个函数当中,首先对事件们做了normalizeEvents标准化处理,然后放到updateListeners里面做更新绑定逻辑的处理

updateListeners

normalizeEvent 首先在normalizeEvent,通过cached函数对event的一些信息(事件名称对应的)做了闭包缓存处理

顺便一提cached工厂函数 cached 工厂函数,接受类型为 【入参string,返回泛形R的函数】作为参数,返回另一个 【入参string,返回泛形R的函数】 可以看到在这里会对目前的vm的事件处理函数用createFnInvoker进行包裹 createFnInvoker

原本的函数就被套用上一层invoker函数,被放到fns属性当中去执行 最后通过add函数去绑定

add

remove

解除的时候,通过removeEventListener进行解绑

在更新绑定事件函数的时候,回到updateListeners,是直接对invoker函数的fns指向进行修改,因此无需重新addEvnetListener进行换绑。达到了优化效果

vue3

vue3当中的入口就是createApp

在patchProps当中的patchEvent环节

patchEvent

createInvoker

这里是重点了,可以看到相对于vue2的invoker,vue3的invoker同样是一个函数,同样的是vue3是直接修改的invoker的value,vue2是修改的fns,其实本质上是一样的,这样造成的结果是:之前绑定的事件处理函数invoker却并没有发生改变!

addEventListener

removeEventListener

小测试

通过模拟vue和传统做法,进行1000000 -1 次事件更新,比较最后的运行时间.

<template>
    <button id="invoker">Vue绑定</button>

    <button id="tradition">传统绑定</button>
</template>

<script>

const invokerBTN = document.getElementById('invoker')

const traditionBTN = document.getElementById('tradition')

const tryTimes = 1000000

const eventInvoker = {

'click':()=>{

        console.log('clicked!');

    }

}

function testTra(){

    console.time('traditional event handler')

    let j = 0

    while(j<tryTimes){

        for(i in eventInvoker){

            traditionBTN.addEventListener(i,eventInvoker[i])

            traditionBTN.removeEventListener(i,eventInvoker[i])

        }

        j  

    }

    console.timeEnd('traditional event handler')

}

// vei = vue event invokers

const vei = {}

function testInvoke(){

    console.time('vue event handler')

    let j = 0

    while(j<tryTimes){

        for(i in eventInvoker){

            let invoker = vei[i]

            if(!invoker){

                invoker = (e)=>{

                    invoker.value && invoker.value(e)

                }

                invoker.value = eventInvoker[i]

                invokerBTN.addEventListener(i,invoker)

                vei[i] = invoker

            }else{

                invoker.value = eventInvoker[i]

            }

        }

        j  

    }

    console.timeEnd('vue event handler')

}

    testTra()

    testInvoke()

</script>

运行结果

可以看到差别还是蛮大的

总结

Vue源码当中对事件的绑定处理,是通过原生api【addEventListener】绑定对应的invoker函数,在invoker内部执行真正的事件处理函数,并且将内部处理函数通过指针暴露出来,从而实现更新时只需更改内存指向即可。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanfekkc
系列文章
更多 icon
同类精品
更多 icon
继续加载