成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

結(jié)合源碼徹底理解 react事件機(jī)制原理 03 - 事件注冊(cè)

chaosx110 / 2185人閱讀

摘要:文章涉及到的源碼是基于版本,雖然不是最新版本但是也不會(huì)影響我們對(duì)事件機(jī)制的整體把握和理解。到這里事件注冊(cè)就完事兒了。

前言

這是 react 事件機(jī)制的第三節(jié) - 事件注冊(cè),通過(guò)本文你將了解react 事件的注冊(cè)過(guò)程,以及在這個(gè)過(guò)程中主要經(jīng)過(guò)了哪些關(guān)鍵步驟,同時(shí)結(jié)合源碼進(jìn)行驗(yàn)證和增強(qiáng)理解。

文章涉及到的源碼是基于 react15.6.1版本,雖然不是最新版本但是也不會(huì)影響我們對(duì) react 事件機(jī)制的整體把握和理解。

文中不會(huì)說(shuō)非常細(xì)節(jié)的內(nèi)容,而是會(huì)把大概的流程和原理性的內(nèi)容進(jìn)行介紹,做到對(duì)整體流程有個(gè)認(rèn)知和理解。

內(nèi)容大綱

主要做兩件事 (事件注冊(cè)、事件存儲(chǔ))

大致流程

具體執(zhí)行過(guò)程

總結(jié)

1. 主要做兩件事

按照我的理解,react 事件注冊(cè)過(guò)程其實(shí)主要做了2件事:

a. 事件注冊(cè)

b. 事件存儲(chǔ)

a. 事件注冊(cè) - 組件掛載階段,根據(jù)組件內(nèi)的聲明的事件類型-onclick,onchange 等,給 document 上添加事件 -addEventListener,并指定統(tǒng)一的事件處理程序 dispatchEvent。

b. 事件存儲(chǔ) - 就是把 react 組件內(nèi)的所有事件統(tǒng)一的存放到一個(gè)地方,也就是緩存起來(lái),可以理解成放入一個(gè)對(duì)象內(nèi),為了在觸發(fā)事件的時(shí)候可以查找到對(duì)應(yīng)的方法去執(zhí)行。

再配個(gè)圖

2. 大致流程

上面大致說(shuō)了事件注冊(cè)需要完成的兩個(gè)目標(biāo),那完成目標(biāo)的過(guò)程需要經(jīng)過(guò)哪些關(guān)鍵處理呢?

首先 react 拿到將要掛載的組件的虛擬 dom(其實(shí)就是 react dom, 類似一個(gè)對(duì)象),然后處理react dom 的 props ,判斷屬性內(nèi)是否有聲明為事件的屬性,比如onclick,這個(gè)時(shí)候得到事件類型 click 和對(duì)應(yīng)的事件處理程序 fn,然后直行后面3步

a. 執(zhí)行事件注冊(cè)

b. 將react dom ,事件類型,處理函數(shù) fn 放入數(shù)組存儲(chǔ)

c. 組件掛載完成后,處理 b 步驟生成的數(shù)組,經(jīng)過(guò)遍歷把事件處理函數(shù)存儲(chǔ)到listenerBank中

再配個(gè)圖

3.具體執(zhí)行過(guò)程

3.1 得先從 jsx 說(shuō)起

看個(gè)最熟悉的代碼,也是我們?nèi)粘5膶懛?/p>

handleFatherClick=()=>{

    }

    handleChildClick=()=>{

    }

    render(){
        return 
child
}

經(jīng)過(guò) babel 編譯后,可以看到最終調(diào)用的方法是react.createElement,而且聲明的事件類型和回調(diào)也是一個(gè)props。

react.createElement執(zhí)行的結(jié)果會(huì)返回一個(gè)所謂的虛擬 dom(react element 或者 react dom),看下圖

3. 2 開(kāi)始處理props,拿到事件類型和回調(diào) fn

ReactDOMComponent在進(jìn)行組件加載(mountComponent)、更新(updateComponent)的時(shí)候,需要對(duì)props進(jìn)行處理(_updateDOMProperties):


可以看下 registrationNameModules 的內(nèi)容,就不細(xì)說(shuō)了。

3.3 注冊(cè)事件和事件的存儲(chǔ)

【注冊(cè)事件】

接著上面的代碼執(zhí)行到了這個(gè)方法

          enqueuePutListener(this, propKey, nextProp, transaction);

在這個(gè)方法里會(huì)進(jìn)行事件的注冊(cè)以及事件的存儲(chǔ),包括冒泡和捕獲的處理

根據(jù)當(dāng)前的組件實(shí)例獲取獲取到最高父級(jí)-也就是document,然后執(zhí)行方法 listenTo - 也是最關(guān)鍵的一個(gè)方法,進(jìn)行事件綁定處理

源碼文件:ReactBrowerEventEmitter.js

最后執(zhí)行EventListener.listen(冒泡)或者EventListener.capture(捕獲),

單看下冒泡的注冊(cè),其實(shí)就是addEventListener的第三個(gè)參數(shù)是 false

也可以看到注冊(cè)事件的時(shí)候也對(duì) ie 做了兼容。

上面沒(méi)有看到 dispatchEvent 的定義,下面可以看到傳入 dispatchEvent 方法的代碼。

到這里事件注冊(cè)就完事兒了。

【事件存儲(chǔ)】

下一步開(kāi)始事件的存儲(chǔ),在 react 里所有事件的觸發(fā)都是通過(guò) dispatchEvent方法統(tǒng)一進(jìn)行派發(fā)的,而不是在注冊(cè)的時(shí)候直接注冊(cè)聲明的回調(diào),來(lái)看下如何存儲(chǔ)的 。

【事件存儲(chǔ)結(jié)論】

react 把所有的事件和事件類型以及react 組件進(jìn)行關(guān)聯(lián),把這個(gè)關(guān)系保存在了一個(gè) map里,也就是一個(gè)對(duì)象里(鍵值對(duì)),然后在事件觸發(fā)的時(shí)候去根據(jù)當(dāng)前的組件id和事件類型查找到對(duì)應(yīng)的事件。

再加個(gè)簡(jiǎn)易圖

看源碼:

function enqueuePutListener(inst, registrationName, listener, transaction) {

  var containerInfo = inst._hostContainerInfo;
  var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE;
  var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument;
  listenTo(registrationName, doc);//這個(gè)方法上面已說(shuō)完


  //這里涉及到了事務(wù),事物會(huì)在以后的章節(jié)再介紹,主要看事件注冊(cè)
  //下面的代碼是將putListener放入數(shù)組,當(dāng)組件掛載完后會(huì)依次執(zhí)行數(shù)組的回調(diào)。也就是putListener會(huì)依次執(zhí)行
  transaction.getReactMountReady().enqueue(putListener, {
    inst: inst,//組件實(shí)例
    registrationName: registrationName,//事件類型 click
    listener: listener //事件回調(diào) fn
  });
}

function putListener() {
  var listenerToPut = this;
  //放入數(shù)組,回調(diào)隊(duì)列
  EventPluginHub.putListener(listenerToPut.inst, listenerToPut.registrationName, listenerToPut.listener);
}

大致的流程就是執(zhí)行完listenTo(事件注冊(cè)),然后執(zhí)行 putListener 方法進(jìn)行事件存儲(chǔ),所有的事件都會(huì)存儲(chǔ)到一個(gè)對(duì)象中 - listenerBank,具體由EventPluginHub進(jìn)行管理。

 //拿到組件唯一標(biāo)識(shí) id
    var getDictionaryKey = function getDictionaryKey(inst) {

      return "." + inst._rootNodeID;

    }

   putListener: function putListener(inst, registrationName, listener) {

    //得到組件 id
        var key = getDictionaryKey(inst);

        //得到listenerBank對(duì)象中指定事件類型的對(duì)象
        var bankForRegistrationName = listenerBank[registrationName] || (listenerBank[registrationName] = {});

        //存儲(chǔ)回調(diào) fn
        bankForRegistrationName[key] = listener;

        //....
  }

listenerBank其實(shí)就是一個(gè)二級(jí) map,這樣的結(jié)構(gòu)更方便事件的查找。

這里的組件 id 就是組件的唯一標(biāo)識(shí),然后和fn 進(jìn)行關(guān)聯(lián),在觸發(fā)階段就可以找到相關(guān)的事件回調(diào)。

看下listenerBank結(jié)構(gòu):

看到這個(gè)結(jié)構(gòu)是不是很熟悉呢?就是我們平常使用的 object.

到這里大致的流程已經(jīng)說(shuō)完,是不是感覺(jué)有點(diǎn)明白又不大明白。

沒(méi)關(guān)系,再來(lái)個(gè)詳細(xì)的圖,重新理解下

4.最后

本文主要是從整體流程上介紹了下 react 事件中事件的注冊(cè)過(guò)程,并沒(méi)有深入到源碼的細(xì)節(jié),有興趣的小伙兒可以自查下源碼,也希望本文能夠帶給你一些啟發(fā),若文章有表述不清或有問(wèn)題的地方歡迎留言交流。

更多精彩內(nèi)容歡迎關(guān)注我的公眾號(hào)-前端張大胖

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104428.html

相關(guān)文章

  • 結(jié)合源碼徹底理解 react事件機(jī)制原理 02 - 對(duì)于合成的理解

    摘要:前言這是事件機(jī)制系列文章的第二篇對(duì)于合成的理解,咱們就來(lái)說(shuō)說(shuō)合成這個(gè)名詞。在給注冊(cè)事件的時(shí)候也是對(duì)兼容性做了處理??偨Y(jié)以上就是我對(duì)于合成這個(gè)名詞的理解,其實(shí)內(nèi)部還處理了很多,我只是略微簡(jiǎn)單的舉了幾個(gè)栗子。 showImg(https://segmentfault.com/img/bVbtvI3?w=1048&h=550); 前言 這是react事件機(jī)制系列文章的第二篇-對(duì)于合成的理解,...

    nihao 評(píng)論0 收藏0
  • 結(jié)合源碼徹底理解 react事件機(jī)制原理 01 - 對(duì)事件機(jī)制的初步理解和驗(yàn)證

    摘要:前言這是事件機(jī)制的第一篇,主要內(nèi)容有表象理解,驗(yàn)證,意義和思考。因?yàn)楹铣墒录挠|發(fā)是基于瀏覽器的事件機(jī)制來(lái)實(shí)現(xiàn)的,通過(guò)冒泡機(jī)制冒泡到最頂層元素,然后再由統(tǒng)一去處理。合成事件的阻止冒泡不會(huì)影響原生事件。 showImg(https://segmentfault.com/img/bVbtvP2?w=800&h=420); 前言 這是 react 事件機(jī)制的第一篇,主要內(nèi)容有:表象理解,驗(yàn)證...

    muddyway 評(píng)論0 收藏0
  • 前端小冊(cè) - 結(jié)合源碼徹底理解 react 事件機(jī)制

    摘要:對(duì)事件機(jī)制的初步理解和驗(yàn)證對(duì)于合成的理解事件注冊(cè)機(jī)制事件執(zhí)行本文基于進(jìn)行分析,雖然不是最新版本但是也不會(huì)影響我們對(duì)事件機(jī)制的整體把握和理解。最后希望通過(guò)本文可以讓你對(duì)事件機(jī)制有更清晰的認(rèn)識(shí)和理解。 showImg(https://segmentfault.com/img/bVbtvI3?w=1048&h=550); 前言 寫這個(gè)文章也算是實(shí)現(xiàn)19年的一個(gè) flag,研究一個(gè)知識(shí)點(diǎn)并且把...

    YJNldm 評(píng)論0 收藏0
  • 結(jié)合源碼徹底理解 react事件機(jī)制原理 04 - 事件執(zhí)行

    摘要:文章涉及到的源碼是基于版本,雖然不是最新版本但是也不會(huì)影響我們對(duì)事件機(jī)制的整體把握和理解??偨Y(jié)本文主要是從整體流程上介紹了下事件觸發(fā)的過(guò)程。 showImg(https://segmentfault.com/img/bVbtvI3?w=1048&h=550); 前言 這是 react 事件機(jī)制的第四節(jié)-事件執(zhí)行,一起研究下在這個(gè)過(guò)程中主要經(jīng)過(guò)了哪些關(guān)鍵步驟,本文也是react 事件機(jī)制...

    marser 評(píng)論0 收藏0
  • 重磅:前端 MVVM 與 FRP 的升階實(shí)踐 —— ReRest 可視化編程

    摘要:是前端開(kāi)發(fā)領(lǐng)域新興的方法論體系,它繼承了與編程理念,在技術(shù)上有不少創(chuàng)新。但專利與開(kāi)源協(xié)議是平行的兩個(gè)世界,改底層也不大容易解決問(wèn)題。此外,要求在中結(jié)合各屬性的是否變化,判斷是否該觸發(fā)更新。 ReRest (Reactive Resource State Transfer) 是前端開(kāi)發(fā)領(lǐng)域新興的方法論體系,它繼承了 MVVM 與 FRP 編程理念,在技術(shù)上有不少創(chuàng)新。本文從專利稿修改而來(lái)...

    Cciradih 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

chaosx110

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<