react源碼分析(3):react的事件委托機(jī)制

在開始之前宗侦,可以先看一下我的另一篇關(guān)于dom本身的事件機(jī)制《談?wù)刯s點(diǎn)擊之后發(fā)生了什么》

前言

????如果你有試過(guò)輸出react事件中的event,你就會(huì)發(fā)現(xiàn)這個(gè)event好像和我們看到的dom事件中的event不太一樣嗅剖,那是因?yàn)閞eact在進(jìn)行dom事件綁定時(shí)辩越,不是直接綁定事件的,而是通過(guò)所謂的合成事件(SyntheticEvent)進(jìn)行委托管理的信粮,它是原生事件進(jìn)行封裝后的結(jié)果黔攒,你可以通過(guò)nativeEvent獲取原生事件。

通過(guò)例子觀察

class App extends Component {
  componentDidMount(){
    document.addEventListener('click', function(){
      console.log('document click')
    })
    document.getElementsByClassName('App')[0].addEventListener('click', function(){
      console.log('app click')
    })
    document.getElementsByTagName('button')[0].addEventListener('click', function(e){
      console.log('button click')
      // e.stopPropagation();
    })
  } 
  onClick = (e) => {
    e.stopPropagation() // 能夠阻止div.app的觸發(fā)
    e.nativeEvent.stopImmediatePropagation(); // 能夠阻止document的觸發(fā)
    e.nativeEvent.stopPropagation(); // 什么都阻止不了
    console.log('react button click');
  };
  render() {
    return (
      <div className="App" onClick={() => {console.log('react app click')}}>
        <button onClick={this.onClick}>按鈕</button>
      </div>
    );
  }
}

我們?cè)谟胷eact綁定了兩個(gè)事件,同時(shí)在didmount給真實(shí)dom也綁定了事件督惰,點(diǎn)擊button之后的執(zhí)行順序是

button click
app click
react button click
react app click
document click

原理

react并不是我之前所設(shè)想的將事件綁定在真實(shí)dom上不傅,而是通過(guò)自己的事件處理器來(lái)處理,將所有的事件都綁定在document上赏胚,這樣真實(shí)點(diǎn)擊的時(shí)候访娶,冒泡到document上,react再通過(guò)document去dispatchEvent統(tǒng)一處理事件

所以上面的stopPropagation就能理解了觉阅,e.stopPropagation只能阻止虛擬dom的事件冒泡崖疤,但它本身是由document觸發(fā)的,所以e.nativeEvent.stopPropagation什么也阻止不了典勇,document就是冒泡的頂點(diǎn)劫哼,e.nativeEvent.stopImmediatePropagation可以阻止document的事件,這和它本身有關(guān)

需要注意的是react在生成真實(shí)的dom節(jié)點(diǎn)會(huì)加入一些東西幫助事件分發(fā)
dom節(jié)點(diǎn)的react屬性(15和16有點(diǎn)區(qū)別)

react15.png

react16.png

15和16會(huì)有一點(diǎn)細(xì)微的區(qū)別割笙,具體什么還沒有去了解权烧,但是看來(lái)對(duì)事件的影響不大,15是有一個(gè)__rootNodeID來(lái)區(qū)分組件伤溉,16是通過(guò)__debugID來(lái)區(qū)分般码,如果理解上有錯(cuò)誤,歡迎指正哦

  • vdom
// 簡(jiǎn)化
let vdom = {
  type: 'div',
  props: {
    onClick: function(){
      console.log('react app click')    
    },
    children: [
      {
        type: 'button',
        props: {
           onClick: function() {
              console.log('react button click')    
           }
        }
      }
    ]
  }
}
  • 注冊(cè)事件
let bankForRegistrationName = {}; // 回調(diào)事件的保存
// react構(gòu)建真實(shí)dom樹
...
// 注冊(cè)事件
bankForRegistrationName = {
    // 數(shù)字是_debugID,react用于識(shí)別每一個(gè)dom
    5: {
      click: function(){
        console.log('react app click')    
      },
    },
    6: {
      click: function(){
        console.log('react button click')    
      },
    }
}
  • 事件觸發(fā)
// 合成事件簡(jiǎn)單實(shí)現(xiàn)
function SyntheticEvent(e) {
  ...
  this.nativeEvent = e;
  ...
}
// e: event乱顾, type: 事件類型
function dispatchEvent(e, type) {
  let synE = new SyntheticEvent(e);
  // 執(zhí)行監(jiān)聽事件
  let debugID = e.target.__reactInternalInstance$om8tco7dvl._debugID;
  bankForRegistrationName[debugID][type](synE); 
}
// document事件委托
document.addEventListener('click', function(e) {
  dispatchEvent(e, 'click');
})

總結(jié)

????基本上就是這樣了(當(dāng)然沒有對(duì)冒泡做處理侈询,react會(huì)遍歷自己的vdom去執(zhí)行冒泡)

  1. 事件管理中心(bankForRegistrationName)會(huì)在react-render過(guò)程中保存所有所有dom事件
  2. document作為事件委托者,用來(lái)分發(fā)事件(dispatchEvent),通過(guò)dom節(jié)點(diǎn)唯一標(biāo)識(shí)(_debugID)去事件管理(bankForRegistrationName)觸發(fā)事件
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糯耍,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子囊嘉,更是在濱河造成了極大的恐慌温技,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扭粱,死亡現(xiàn)場(chǎng)離奇詭異舵鳞,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)琢蛤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門蜓堕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人博其,你說(shuō)我怎么就攤上這事套才。” “怎么了慕淡?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵背伴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)傻寂,這世上最難降的妖魔是什么息尺? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮疾掰,結(jié)果婚禮上搂誉,老公的妹妹穿的比我還像新娘。我一直安慰自己静檬,他們只是感情好炭懊,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著巴柿,像睡著了一般凛虽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上广恢,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天凯旋,我揣著相機(jī)與錄音,去河邊找鬼钉迷。 笑死至非,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的糠聪。 我是一名探鬼主播荒椭,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舰蟆!你這毒婦竟也來(lái)了趣惠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤身害,失蹤者是張志新(化名)和其女友劉穎味悄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體塌鸯,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侍瑟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丙猬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涨颜。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖茧球,靈堂內(nèi)的尸體忽然破棺而出庭瑰,到底是詐尸還是另有隱情,我是刑警寧澤抢埋,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布见擦,位于F島的核電站钉汗,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鲤屡。R本人自食惡果不足惜损痰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酒来。 院中可真熱鬧卢未,春花似錦、人聲如沸堰汉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翘鸭。三九已至滴铅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間就乓,已是汗流浹背汉匙。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留生蚁,地道東北人噩翠。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像邦投,于是被迫代替她去往敵國(guó)和親伤锚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • ??JavaScript 與 HTML 之間的交互是通過(guò)事件實(shí)現(xiàn)的。 ??事件念脯,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,500評(píng)論 1 11
  • 安裝 使用 在命令行上玄呛,運(yùn)行TypeScript編譯器:輸出結(jié)果為一個(gè)a.js文件,它包含了和輸入文件中相同的Ja...
    woow_wu7閱讀 2,436評(píng)論 0 1
  • 本文使用的是react 15.6.1的代碼 我們先看一段代碼 當(dāng)我們點(diǎn)擊按鈕的時(shí)候和二,會(huì)彈出哪一些框?答案是分別彈出...
    Kaku_fe閱讀 627評(píng)論 0 4
  • 事件是一種異步編程的實(shí)現(xiàn)方式耳胎,本質(zhì)上是程序各個(gè)組成部分之間的通信惯吕。DOM支持大量的事件,本節(jié)介紹DOM的事件編程怕午。...
    周花花啊閱讀 593評(píng)論 0 3
  • 本文通過(guò)一個(gè)簡(jiǎn)短的實(shí)例&控制臺(tái)調(diào)試废登,了解react事件處理的全過(guò)程。下面是測(cè)試用代碼郁惜,使用控制臺(tái)可以清晰看到函數(shù)執(zhí)...
    溪離欣洛閱讀 1,217評(píng)論 2 2