扎實(shí)前端系列:簡(jiǎn)單卻容易誤解的事件流

事件流的概念不復(fù)雜讨衣,卻很容易誤解方援。同樣没炒,如果你覺(jué)得自己掌握的清楚,可以嘗試猜猜下面的幾個(gè)例子的輸出結(jié)果會(huì)是什么樣犯戏。

事件流的兩種模型

冒泡和捕獲是事件流的兩種模型

  • 事件冒泡(event bubbling)是IE的提出的事件流
  • 事件捕獲(event capturing)是 Netscape Communicator提出的事件流送火。

其中目前瀏覽器采用的默認(rèn)是冒泡型。

事件流包含三個(gè)階段:

  • 事件捕獲階段
  • 處于目標(biāo)階段
  • 事件冒泡階段先匪。

不論哪種事件模型包含著三個(gè)階段种吸,差異在于在什么階段處理事件。

我們可以在事件的處理程序中呀非,通過(guò)event.eventPhase來(lái)獲取到處理程序所在的階段:

  • value=1 捕獲階段
  • value=2 處于目標(biāo)
  • value=3 冒泡階段

需要澄清的概念

我們假定DOM元素是層層包裹的洋蔥骨稿,假定DOM結(jié)構(gòu)為:

<body>
    <div>
        <span>here is span content</span>   
    </div>
</body> 

加入點(diǎn)擊了span元素,那么在捕獲階段事件的傳遞序列為:body -> div姜钳;在處于目標(biāo)階段,事件停留在span形耗;在冒泡階段哥桥,事件的傳遞序列為:div -> body。

我們?cè)谌我庖粋€(gè)DOM上點(diǎn)擊激涤,比如點(diǎn)擊span拟糕,或點(diǎn)擊div但不點(diǎn)擊到span,如果該DOM上有事件處理程序倦踢,event.eventPhase必然為2送滞。

結(jié)論一:直接點(diǎn)擊元素,并觸發(fā)它上面的事件處理程序辱挥,eventPhase一定等于2犁嗅。

我們能得到event.eventPhase不為2的結(jié)果,一定是點(diǎn)擊元素 和 綁定了事件處理程序的不是同一個(gè)元素晤碘。

先來(lái)個(gè)簡(jiǎn)單的例子:

<button id="testBtn""><i>mockicon</i>&nbsp;Click Me</button>
<script>
  const btn = document.getElementById('testBtn');
  btn.addEventListener('click', function(e){
    const evt = e || event;
    console.log(evt.eventPhase);
  }/*,true*/)
</script>

(1)定義了一個(gè) button褂微,在它上面綁定點(diǎn)擊事件,直接點(diǎn)擊它园爷,事件處理程序獲取到的 event.eventPhase 是 2

(2)按鈕內(nèi)部有一個(gè)<i class="icon"></i>宠蚂,點(diǎn)擊按鈕中的i,事件處理程序獲取到的 event.eventPhase 是 3

(3)如果通過(guò)addEventListener指定第三個(gè)參數(shù)為true童社,采用事件捕獲的事件流求厕,點(diǎn)擊按鈕中的i,事件處理程序獲取到的 event.eventPhase 是1

在(2)中之所以輸出為3,是因?yàn)槭录诓东@呀癣、冒泡階段都經(jīng)過(guò)了div美浦,但是在冒泡階段才被處理;(3)則是在捕獲階段就被處理了十艾。

結(jié)論二:在子元素上點(diǎn)擊抵代,觸發(fā)父元素的點(diǎn)擊事件,事件對(duì)象上的eventPhase為3忘嫉;點(diǎn)擊事件用捕獲模型荤牍,則eventPhase為1

務(wù)必記住的一點(diǎn)是,eventPhase為2只屬于直接點(diǎn)擊的元素庆冕。

你完全懂了嗎

拿下面的4個(gè)例子玩一玩康吵,看你是否能理解輸出結(jié)果。如下是頁(yè)面的css和html結(jié)構(gòu)访递。

<style>
  div {
    border: 3px solid red;
    padding: 15px;
    width: 500px;
    border-radius: 5px;
    margin-bottom: 5px;
  }
  h3 {
    border: 2px solid green;
  }
  pre {
    border: 1px solid gray;
    padding: 5px;
  }
</style>

<div>
  <h3></h3>
  <pre></pre>
</div>

1. 只在父元素上綁定點(diǎn)擊事件

flow-1
<div id="c1" onclick="handler(event)">
  <h3 id="t1"> 測(cè)試 #1 只在父元素上綁定點(diǎn)擊事件</h3>
  <pre>
    點(diǎn)擊子元素H3 或 PRE:
    DIV clicked, phase = 3

    點(diǎn)擊其他空白區(qū)域:
    DIV clicked, phase = 2
  </pre>
</div>


<script>
  function handler(event) {
    console.log(event.currentTarget.nodeName + ' clicked, phase = ' + event.eventPhase);
  }
</script>

按照結(jié)論二晦嵌,點(diǎn)擊h3或pre,自身沒(méi)有事件處理拷姿,只會(huì)冒泡到div上惭载,從而eventPhase輸出為3。

按照結(jié)論一响巢,點(diǎn)擊div內(nèi)的空白區(qū)域描滔,相當(dāng)于直接點(diǎn)擊div元素,輸出eventPhase為1踪古。

2. 在父含长、子元素上都綁定點(diǎn)擊事件

flow-2
<div id="c2" onclick="handler(event)">
  <h3 id="t2" onclick="handler(event)">測(cè)試 #2 在父、子元素上都綁定點(diǎn)擊事件</h3>
  <pre>
    點(diǎn)擊子元素H3:
    H3 clicked, phase = 2
    DIV clicked, phase = 3

    點(diǎn)擊子元素PRE
    DIV clicked, phase = 3

    點(diǎn)擊非子元素的空白區(qū)域:
    DIV clicked, phase = 2
  </pre>
</div>


<script>
  function handler(event) {
    console.log(event.currentTarget.nodeName + ' clicked, phase = ' + event.eventPhase);
  }
</script>

相對(duì)上一個(gè)例子的唯一變化是伏穆,h3上也綁定了事件處理程序拘泞,這里唯一變化的是點(diǎn)擊h3的時(shí)候的輸出。

結(jié)合結(jié)論一枕扫、二陪腌,在h3點(diǎn)擊時(shí),先觸發(fā)h3的eventPhase為2铡原,然后再冒泡到div上eventPhase為3偷厦。

3. 捕獲方式只在父元素上綁定點(diǎn)擊事件

flow-3
<div id="c3">
  <h3 id="t3">  測(cè)試 #3 捕獲方式只在父元素上綁定點(diǎn)擊事件</h3>
  <pre>
    點(diǎn)擊子元素H3:
    DIV clicked, phase = 1

    點(diǎn)擊非子元素的空白區(qū)域:
    DIV clicked, phase = 2
  </pre>
</div>

<script>
  function handler(event) {
    console.log(event.currentTarget.nodeName + ' clicked, phase = ' + event.eventPhase);
  }
  
  var c3 = document.getElementById('c3');
  c3.addEventListener('click', handler, true);
</script>

代碼跟例子一一樣,只是捕獲的方式從冒泡修改為了捕獲燕刻。

根據(jù)結(jié)論二只泼,點(diǎn)擊h3的時(shí)候,早于事件到達(dá)h3卵洗,就在div被捕獲了请唱,輸出為div eventPhase為1弥咪。

點(diǎn)擊空白區(qū)域,則仍舊滿(mǎn)足結(jié)論一十绑。

自己曾經(jīng)不能理解聚至,雖然點(diǎn)擊的是h3,但是點(diǎn)擊先作用在洋蔥的外層(div)上本橙,為什么eventPhase不會(huì)是2扳躬,這里繼續(xù)澄清:

eventPhase的值,在“真正”被點(diǎn)擊的元素上是2甚亭,之前都是1贷币,之后都是3。

4. 在父亏狰、子元素上綁定捕獲型點(diǎn)擊事件

flow-4
<div id="c4">
  <h3 id="t4"> 測(cè)試 #4 捕獲方式在父役纹、字元素上都綁定點(diǎn)擊事件</h3>
  <pre>
    點(diǎn)擊子元素H3:
    DIV clicked, phase = 1
    H3 clicked, phase = 2
    
    點(diǎn)擊非子元素的空白區(qū)域:
    DIV clicked, phase = 2
  </pre>
</div>


<script>
  function handler(event) {
    console.log(event.currentTarget.nodeName + ' clicked, phase = ' + event.eventPhase);
  }

  var c4 = document.getElementById('c4');
  var t4 = document.getElementById('t4');
  c4.addEventListener('click', handler, true);
  t4.addEventListener('click', handler, true);
</script>

根據(jù)結(jié)論二:點(diǎn)擊h3的時(shí)候,會(huì)先在捕獲階段出發(fā)div eventPhase為1的輸出暇唾,然后到達(dá)h3 eventPhase為2的輸出促脉。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市策州,隨后出現(xiàn)的幾起案子瘸味,更是在濱河造成了極大的恐慌,老刑警劉巖够挂,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硫戈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡下硕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)汁胆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)梭姓,“玉大人,你說(shuō)我怎么就攤上這事嫩码∮猓” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵铸题,是天一觀的道長(zhǎng)铡恕。 經(jīng)常有香客問(wèn)我,道長(zhǎng)丢间,這世上最難降的妖魔是什么探熔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮烘挫,結(jié)果婚禮上诀艰,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好其垄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布苛蒲。 她就那樣靜靜地躺著,像睡著了一般绿满。 火紅的嫁衣襯著肌膚如雪臂外。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,708評(píng)論 1 305
  • 那天喇颁,我揣著相機(jī)與錄音漏健,去河邊找鬼。 笑死无牵,一個(gè)胖子當(dāng)著我的面吹牛漾肮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茎毁,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼克懊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了七蜘?” 一聲冷哼從身側(cè)響起谭溉,我...
    開(kāi)封第一講書(shū)人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎橡卤,沒(méi)想到半個(gè)月后扮念,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碧库,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年柜与,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嵌灰。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡弄匕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沽瞭,到底是詐尸還是另有隱情迁匠,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布驹溃,位于F島的核電站城丧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏豌鹤。R本人自食惡果不足惜亡哄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望布疙。 院中可真熱鬧磺平,春花似錦魂仍、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至菠劝,卻和暖如春赊舶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赶诊。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工笼平, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舔痪。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓寓调,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锄码。 傳聞我的和親對(duì)象是個(gè)殘疾皇子夺英,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355