JavaScript中的事件傳播(DOM2標(biāo)準(zhǔn)事件模型)

  • 在所有現(xiàn)代瀏覽器當(dāng)中——除了IE9之前的版本——都實(shí)現(xiàn)了DOM2標(biāo)準(zhǔn)事件模型旋恼,這個事件模型規(guī)定昼牛,每一個DOM元素所觸發(fā)的事件泛鸟,都要經(jīng)歷三個階段:一蝠咆、捕獲階段;二北滥、目標(biāo)對象本身的事件處理程序調(diào)用階段刚操;三、冒泡階段碑韵。

  • 冒泡階段:當(dāng)文檔元素上發(fā)生某個類型的事件時赡茸,他們會在文檔樹上向上傳播。(即調(diào)用父元素相同類型的事件處理函數(shù))祝闻。

  • 捕獲階段:捕獲階段像反向的冒泡階段占卧。最先調(diào)用window對象的捕獲處理程序,然后是Document對象的捕獲處理程序联喘,接著是body對象的华蜒,再然后是DOM樹向下,以此類推豁遭,直到調(diào)用事件目標(biāo)元素的父元素的捕獲處理程序叭喜。在目標(biāo)元素對象本身上注冊的捕獲事件處理程序,不會被調(diào)用蓖谢。

  • 在DOM2標(biāo)準(zhǔn)事件模型中捂蕴,為一個DOM元素綁定事件的方法為addEventListener(),這個方法要求傳遞三個參數(shù):
    1、第一個參數(shù)為一個字符串闪幽,表示事件類型啥辨,如"click";
    2盯腌、第二個參數(shù)是一個函數(shù)溉知,表示事件處理程序,瀏覽器會默認(rèn)為該函數(shù)傳遞一個事件對象(Event);
    3腕够、第三個參數(shù)是一個布爾值级乍,布爾值為false,表示此函數(shù)將注冊為冒泡事件處理程序(通常設(shè)置為false即可)帚湘,如果值為true玫荣,表示此函數(shù)將注冊為捕獲事件處理程序。值得注意的是大诸,能通過多次調(diào)用addEventListener ()為同一個對象注冊同一事件類型的多個處理程序函數(shù)崇决。當(dāng)對象上發(fā)生事件時材诽,所有該事件類型的注冊處理程序,都會按照注冊的順序調(diào)用恒傻。

分析事件的觸發(fā)過程,分兩種情況:

  1. 當(dāng)目標(biāo)元素不存在父元素或目標(biāo)元素的父元素并沒有注冊與觸發(fā)目標(biāo)元素相同類型的事件時建邓,事件模型的第一和第三個節(jié)點(diǎn)是沒有實(shí)際意義的(即不會發(fā)生任何事情)盈厘;
  2. 當(dāng)目標(biāo)元素存在父元素且目標(biāo)元素的父元素注冊了與觸發(fā)目標(biāo)元素相同類型的事件時,事件模型的第一個和第三個階段就開始起作用了:

為了方便官边,先將以下示例中頁面效果截圖如下沸手,所有示例的頁面效果都是如此:


image.png

html中頁面效果
html:

<div id="eventSpreadDiv" style="padding:20px;background-color:red;width:300px;">
<button id="eventSpreadBtn" type="button">eventSpreadBtn</button>&nbsp;&nbsp;&nbsp;eventSpreadDiv
</div>

(1) 父元素注冊捕獲事件,子元素不注冊事件:
js:

document.getElementById("eventSpreadDiv").addEventListener("click", function(e) {console.log(e.currentTarget.id);}, true);

控制臺輸出:
點(diǎn)擊div(紅色區(qū)域):

eventSpreadDiv  

點(diǎn)擊button:

eventSpreadDiv  

分析:
當(dāng)點(diǎn)擊div時注簿,出現(xiàn)的是事件觸發(fā)過程的情況1:目標(biāo)元素不存在父元素契吉,所以只執(zhí)行了注冊在eventSpreadDiv上的click方法,此時e.currentTarget就是eventSpreadDiv诡渴;
當(dāng)點(diǎn)擊button時捐晶,出現(xiàn)的是事件觸發(fā)過程的情況2:目標(biāo)元素(此時是button)的父元素(div)注冊了與觸發(fā)目標(biāo)元素相同類型的事件(click事件),又因?yàn)閐iv上注冊的click事件的類型為捕獲事件妄辩,所以當(dāng)事件模型進(jìn)行第一階段時棍辕,先執(zhí)行了div的click事件溺森,此時e.currentTarget就是eventSpreadDiv;然后執(zhí)行第二階段,即目標(biāo)元素button的click事件(并無注冊事件)电媳;接下來是第三階段冒泡階段(也沒有相應(yīng)的函數(shù)調(diào)用)。

(2)父元素注冊冒泡事件萄涯,子元素不注冊事件:
js:

document.getElementById("eventSpreadDiv").addEventListener("click", function(e) {console.log(e.currentTarget.id);}, false);

控制臺輸出:
點(diǎn)擊div(紅色區(qū)域):

eventSpreadDiv 

點(diǎn)擊button:

eventSpreadDiv

分析:當(dāng)點(diǎn)擊div時陈肛,出現(xiàn)的是事件觸發(fā)過程的情況1:目標(biāo)元素不存在父元素,所以只執(zhí)行了注冊在eventSpreadDiv上的click方法楞黄,此時e.currentTarget就是eventSpreadDiv池凄;當(dāng)點(diǎn)擊button時,出現(xiàn)的是事件觸發(fā)過程的情況2:目標(biāo)元素(此時是button)的父元素(div)注冊了與觸發(fā)目標(biāo)元素相同類型的事件(click事件)谅辣,又因?yàn)閐iv上注冊的click事件的類型為冒泡事件修赞,所以事件模型進(jìn)行第一階段時沒有相應(yīng)的函數(shù)調(diào)用;然后執(zhí)行第二階段桑阶,即目標(biāo)元素button的click事件(并無注冊事件)柏副;接下來是第三階段冒泡階段,此時執(zhí)行了div的click事件蚣录,e.currentTarget就是eventSpreadDiv割择。
(3)父元素注冊捕獲事件和冒泡事件,子元素注冊click事件
js:
document.getElementById("eventSpreadBtn").addEventListener("click", function(e){console.log(e.currentTarget.id)}, false);
document.getElementById("eventSpreadDiv").addEventListener("click", function(e) {console.log("冒泡" + e.currentTarget.id);}, false);
document.getElementById("eventSpreadDiv").addEventListener("click", function(e) {console.log("捕獲" + e.currentTarget.id);}, true);
控制臺輸出:
點(diǎn)擊div(紅色區(qū)域):

冒泡eventSpreadDiv  
捕獲eventSpreadDiv  

點(diǎn)擊button:

捕獲eventSpreadDiv  
eventSpreadBtn  
冒泡eventSpreadDiv 

分析:當(dāng)點(diǎn)擊div時萎河,出現(xiàn)的是事件觸發(fā)過程的情況1:目標(biāo)元素不存在父元素荔泳,所以只執(zhí)行了注冊在eventSpreadDiv上的click方法蕉饼,但是,此時div被注冊了兩個click方法玛歌,所以昧港,click事件其實(shí)被觸發(fā)了兩次,調(diào)用順序?yàn)榇a的注冊順序(即先調(diào)用第一個被注冊的冒泡事件再調(diào)用第二個被注冊的捕獲事件)支子,這兩個事件執(zhí)行時的e.currentTarget都是div创肥;當(dāng)點(diǎn)擊button時,出現(xiàn)的是事件觸發(fā)過程的情況2:目標(biāo)元素(此時是button)的父元素(div)注冊了與觸發(fā)目標(biāo)元素相同類型的事件(click事件)值朋,又因?yàn)閐iv上既注冊了事件類型為click的捕獲事件叹侄,又注冊了事件類型為click的冒泡事件,所以當(dāng)事件模型進(jìn)行第一階段時昨登,執(zhí)行了div的click捕獲事件趾代,此時e.currentTarget就是eventSpreadDiv;然后執(zhí)行第二階段丰辣,即目標(biāo)元素button的click事件撒强,此時e.currentTarget就是button;接下來是第三階段冒泡階段糯俗,執(zhí)行了div的click冒泡事件尿褪,此時e.currentTarget就是eventSpreadDiv。
總結(jié):DOM2標(biāo)準(zhǔn)事件模型得湘,為我們編寫JavaScript事件驅(qū)動型的程序提供了更靈活的方案杖玲,比如我們可以在捕獲階段和冒泡階段來阻止事件的繼續(xù)傳播(詳情請看上一篇),也可利用這一模型進(jìn)行代碼的調(diào)試淘正。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摆马,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸿吆,更是在濱河造成了極大的恐慌囤采,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惩淳,死亡現(xiàn)場離奇詭異蕉毯,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)思犁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門代虾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人激蹲,你說我怎么就攤上這事棉磨。” “怎么了学辱?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵乘瓤,是天一觀的道長环形。 經(jīng)常有香客問我,道長衙傀,這世上最難降的妖魔是什么抬吟? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮统抬,結(jié)果婚禮上拗军,老公的妹妹穿的比我還像新娘。我一直安慰自己蓄喇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布交掏。 她就那樣靜靜地躺著妆偏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盅弛。 梳的紋絲不亂的頭發(fā)上钱骂,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機(jī)與錄音挪鹏,去河邊找鬼见秽。 笑死,一個胖子當(dāng)著我的面吹牛讨盒,可吹牛的內(nèi)容都是我干的解取。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼返顺,長吁一口氣:“原來是場噩夢啊……” “哼禀苦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起遂鹊,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤振乏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秉扑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體慧邮,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年舟陆,在試婚紗的時候發(fā)現(xiàn)自己被綠了误澳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡吨娜,死狀恐怖脓匿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宦赠,我是刑警寧澤陪毡,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布米母,位于F島的核電站,受9級特大地震影響毡琉,放射性物質(zhì)發(fā)生泄漏铁瞒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一桅滋、第九天 我趴在偏房一處隱蔽的房頂上張望慧耍。 院中可真熱鬧,春花似錦丐谋、人聲如沸芍碧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽泌豆。三九已至,卻和暖如春吏饿,著一層夾襖步出監(jiān)牢的瞬間踪危,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工猪落, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贞远,地道東北人。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓笨忌,卻偏偏與公主長得像蓝仲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蜜唾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評論 2 361

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

  • ??JavaScript 與 HTML 之間的交互是通過事件實(shí)現(xiàn)的袁余。 ??事件擎勘,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,502評論 1 11
  • js之事件機(jī)制 1、事件初探 1.1 js事件的概述 JavaScript事件:JavaScript是基于事件驅(qū)動...
    道無虛閱讀 2,374評論 1 3
  • 事件是一種異步編程的實(shí)現(xiàn)方式颖榜,本質(zhì)上是程序各個組成部分之間的通信棚饵。DOM支持大量的事件,本節(jié)介紹DOM的事件編程掩完。...
    許先生__閱讀 948評論 0 3
  • 第13章 事件 1. 事件流 事件流描述的是從頁面中接收事件的順序噪漾。 (1) 事件冒泡 IE 的事件流叫做事件冒泡...
    yinxmm閱讀 954評論 0 17
  • Dom事件 事件是一種異步編程的實(shí)現(xiàn)方式,本質(zhì)上是程序各個組成部分之間的通信且蓬。DOM支持大量的事件 (一) Eve...
    woow_wu7閱讀 1,778評論 0 1