javascript 事件傳播與事件冒泡,W3C事件模型
說實話筆者在才工作的時候就聽說了什么"事件冒泡",弄了很久才弄個大概,當時理解意思是子級dom元素和父級dom元素都綁定了相同類型的事件,這時如果子級事件觸發了父級也會觸發,然后這就叫做"事件冒泡"。然而,事情要是這么簡單的話,相信筆者這時一定已經迎娶了白富美,當上了CEO。壞就壞在后來又聽說一個"事件傳播" ,尼瑪不是"事件冒泡"嗎,然后又聽說了"W3C事件模型"。。。到了最后筆者徹底心碎了,只能乖乖的當忙農了!!!
咱們先說說里面的術語," 事件捕獲 "、" 事件冒泡 "、" 事件傳播 "、" 事件注冊 "、" W3C事件模型 "
" 事件注冊 ":事件注冊有好多方式,大概有下面這些
1、直接在dom元素上加,這其實是很挫的方式,然并卵,現在仍然有好多淫在用
<input type="button" onclick="alert('打的好')" name="button" value="痛擊我啊">
2、使用js程序在dom元素對象上加"onxxx"的形式
<input type="button" id="btn" name="button" value="痛擊我啊"> document.getElementById('btn').onclick = function(){alert('打的好');};
3、使用諸如'addEventListener'、'attachEvent'函數
var dom = document.getElementById('btn'); var hander = function(){alert('打的好');}; if(dom.addEventListener){ dom.addEventListener('click', hander, false);//支持標準w3c瀏覽器專用 }else{ dom.attachEvent('onclick', hander);//非標準w3c瀏覽器專用 }
4、逼格更加高點的"事件委托",意思就是委托別人幫助自己響應事件,如下
<div id="father" style="background: green;"> 我是父親啊</br> 呵呵啊</br> <div id="son" style="background: blue;"> 我是兒子啊 </div> </div>
document.getElementById('father').onclick = function(event){ event = event || window.event; var target = event.srcElement || event.target; if(target.getAttribute('id') === 'son'){ alert('你點擊了兒子!');} }
點擊"我是兒子啊"彈出框框,點擊"我是父親啊" 什么都沒有彈,當然了,你不僅可以委托父級元素,也可以委托和你無關的元素
" 事件冒泡 " 和 " 事件傳播 ":
兩個一起說了,是有歷史原因的,早期有兩冤家,網景和微軟,它倆啥都對著干,網景搞"事件傳播",微軟對著干搞"事件冒泡",這倆貨有啥區別了,網上有人專門畫了一張圖
"事件冒泡"就是那個綠色的箭頭,"事件傳播"就是那個紅色的箭頭
"事件冒泡"就從目標元素"td"一直冒到根"window", "事件傳播"就從根"window"一直傳到"td"元素, 是不是編程都反著干,真是冤家
這時候聯合國"w3c"來了, 這不行啊,不能由著他們亂搞啊,不然這天下不就亂了,但是這兩家伙實力比較強,又不能不考慮他們啊,于是W3C采用中和方案制定標準,規定" 任何事件首先向下傳播直到遇到目標元素,然后再向上冒泡返回 " ,這注意好這問題統一了,并且都照顧了大家,我這秘書長位置穩保!!!
所以,你上面看到了兩個函數"attachEvent" 和 "addEventListener", 其中"attachEvent"是IE8及其之前的IE瀏覽器專用,只支持"事件冒泡","addEventListener" 是所有支持
W3C標準事件模型的瀏覽器專用,即支持"事件冒泡" 又支持 "事件傳播"。那對應的取消事件綁定就是 "detachEvent"和"removeEventListener" 兩個函數了。那上面那個"event = event || window.event" 也是兼容瀏覽器用的了,因為IE8及其之前的IE瀏覽器不能直接獲取event對象,需要從window對象獲取。
那這個"事件傳播"與"事件冒泡" 有啥實際上的區別了,我們還是以一段代碼來證明(由于IE8及之前的瀏覽器只支持"事件冒泡",因此我們這里用chrome瀏覽器測試)
先HTML代碼
<div id="father" style="background: green;"> 我是父親啊</br> 呵呵啊</br> <div id="son" style="background: blue;"> 我是兒子啊 </div> </div>
界面是
document.getElementById('father').addEventListener('click', function(){ alert('我是父親!'); }, true);//在事件傳播階段捕獲 document.getElementById('son').addEventListener('click', function(event){ alert('我是兒子!'); }, true);//在事件傳播階段捕獲
點擊"我是兒子啊" 是不是會彈出兩次,然后我們換成下面這段再看會彈出幾次
document.getElementById('father').addEventListener('click', function(){ alert('我是父親!'); event.stopPropagation(); }, true); document.getElementById('son').addEventListener('click', function(event){ alert('我是兒子!'); }, true);
這次只彈出了一次"我是父親" , "我是兒子" 那句沒有執行,這是啥原因了?
因為這里設定在事件傳播階段捕獲事件,事件是先傳播到'father'元素中的,在'father'元素中調用了'event.stopPropagation()'阻止事件進一步捕獲,因此事件將不再傳播到'son'元素中 ( 注意,好多淫把阻止事件傳播或者冒泡 與 阻止默認事件 弄混淆了, 阻止默認事件的函數為 'preventDefault' 和 'returnValue = false;', 一個W3C標準瀏覽器專用,一個IE8及之前版本的IE專用 )
再來看在事件冒泡階段進行捕獲,會是怎樣的結果,代碼如下
document.getElementById('father').addEventListener('click', function(){ alert('我是父親!'); }, false); document.getElementById('son').addEventListener('click', function(event){ alert('我是兒子!'); event.stopPropagation(); }, false);
這次再點擊"我是兒子啊" 只彈出了"我是兒子","我是父親" 沒有彈出,這是啥原因了?
因為上面代碼設定了在事件冒泡階段捕獲,事件先進入傳播階段 傳播到'fanther', 'son' 然后到達目標元素 'son', 然后按照W3C的規定 以 事件冒泡 方式返回,先是到達'son', 但是在'son'這里被阻止了,因此不再往上冒泡,只能捕獲'son'中的事件了
" 事件捕獲 ":看了上面那么多,鄙人覺得這個就不用解釋了吧
" W3C事件模型 ":這個,筆者貌似在上面也解釋了,不用說了吧
鄙人才疏學淺,有不足之處,歡迎補足!!!