原由:正常狀況下我點擊s2時是先彈出我是children,再彈出我是father,可是卻出現了先彈出我是father,後彈出我是children的狀況,這種狀況是在和安卓app交互的h5頁面中出現的,本地測試沒有問題,可是在安卓打包的內嵌h5頁面就出現了問題。簡單化的代碼先展現出來。javascript
html代碼以下html
<div id="father" class="ss1">s1 <div id="children" class="ss2">s2 </div> </div>
事件綁定以下java
$('#father').on('click',function (e) { alert('我是father') }) $('#children').on('click',function (e) { alert('我是children') e.stopPropagation(); })
藉此問題,複習了一下js事件,先看一下幾個定義node
// IE之外的其餘瀏覽器 // target :文檔節點、document、window 或 XMLHttpRequest。 // type :字符串,事件名稱,不含「on」,好比「click」、「mouseover」、「keydown」等。 // listener :實現了 EventListener 接口或者是 JavaScript 中的函數。 // useCapture :是否使用捕捉,通常用 false,事件觸發時,會將一個 Event 對象傳遞給事件處理程序。 target.addEventListener(type,listener,useCapture);//添加 target.removeEventListener(type,listener,useCapture);//刪除
// IE瀏覽器 // target :文檔節點、document、window 或 XMLHttpRequest。 // type :字符串,事件名稱,含「on」,好比「onclick」、「onmouseover」、「onkeydown」等。 // listener :實現了 EventListener 接口或者是 JavaScript 中的函數。 target.attachEvent(type, listener);//添加 target.detachEvent(type, listener);// 移除
兼容後的方法 var func = function(){}; //例:addEvent(window,"load",func) function addEvent(elem, type, fn) { if (elem.attachEvent) { elem.attachEvent('on' + type, fn); return; } if (elem.addEventListener) { elem.addEventListener(type, fn, false); } } //例:removeEvent(window,"load",func) function removeEvent(elem, type, fn) { if (elem.detachEvent) { elem.detachEvent('on' + type, fn); return; } if (elem.removeEventListener) { elem.removeEventListener(type, fn, false); } }
function eventHandler(e){ //獲取事件對象 e = e || window.event;//IE和Chrome下是window.event FF下是e //獲取事件源 var target = e.target || e.srcElement;//IE和Chrome下是srcElement FF下是target }
myTable.onclick = function () { e = e || window.event; var targetNode = e.target || e.srcElement; // 測試若是點擊的是TR就觸發 if (targetNode.nodeName.toLowerCase() === 'tr') { alert('You clicked a table row!'); } }
和事件的綁定實際上是相對應的,若是須要接觸事件的綁定,運行對應的函數就能夠了。若是是原生JS綁定則對應運行removeEventListener()和detachEvent()。瀏覽器
若是是jQuery的bind()和delegate()綁定,也是存在對應的解綁函數用以清除註冊事件,好比unbind()和undelegate()。網絡
看一個代碼示例:app
var EventUtil = { //註冊 addHandler: function(element, type, handler){ if (element.addEventListener){ element.addEventListener(type, handler, false); } else if (element.attachEvent){ element.attachEvent("on" + type, handler); } else { element["on" + type] = handler; } }, //移除註冊 removeHandler: function(element, type, handler){ if (element.removeEventListener){ element.removeEventListener(type, handler, false); } else if (element.detachEvent){ element.detachEvent("on" + type, handler); } else { element["on" + type] = null; } } };
幾個概念dom
捕獲階段:事件對象經過目標的祖先從傳播窗口到目標的父。這個階段也被稱爲捕獲階段。異步
目標階段:本次活動對象到達事件對象的事件的目標。這個階段也被稱爲目標階段。若是事件類型指示事件不起泡,則在完成此階段後,事件對象將中止。函數
冒泡階段:事件對象經過目標的祖先中傳播以相反的順序,開始與目標的父和與所述結束窗口。這個階段也被稱爲冒泡階段。
默認行爲:事件一般由實現做爲用戶操做的結果分派,以響應任務的完成,或者在異步活動(例如網絡請求)期間發信號通知進度。有些事件能夠用來控制下一個實現可能採起的行爲(或者撤銷實現已經採起的行動)。這個類別中的事件被認爲是可取消的,他們取消的行爲被稱爲他們的默認行爲。
取消事件:可取消的事件對象能夠與一個或多個「默認動做」相關聯。要取消事件,請調用該preventDefault()
方法。
一個圖片
再上個小demo
<ul> <li>點我試試</li> </ul> <div id="s1" class="ss1">s1 <div id="s2" class="ss2">s2</div> </div>
var ul = document.getElementsByTagName('ul')[0]; var li = document.getElementsByTagName('li')[0];
element.addEventListener(event, function, useCapture) document.addEventListener('click',function(e){console.log('document clicked')},true);//第三個參數爲true使用捕獲,false爲冒泡,false爲默認 ul.addEventListener('click',function(e){console.log('ul clicked')},true); li.addEventListener('click',function(e){console.log('li clicked')},true); //IE低版本兼容寫法 li.attachEvent('onclick',function(event){ debugger console.log('li clicked'); event.cancelBubble=true; }); s1.addEventListener('click',function () { console.log('s1 捕獲方式') },true) s1.addEventListener('click',function () { console.log('s1 冒泡方式') },false) s2.addEventListener('click',function (e) { console.log('s2 捕獲方式') // e.stopPropagation(); },true) s2.addEventListener('click',function () { console.log('s2 冒泡方式') },false)
點擊li時,打印 依次爲
ul clicked li clicked
點擊s1時,打印依次爲
s1 捕獲方式 s1 冒泡方式
點擊s2時,打印依次爲
s1 捕獲方式 s2 捕獲方式 s2 冒泡方式 s1 冒泡方式
一、e.preventDefault()
var a = document.getElementById("testA"); a.onclick =function(e){ if(e.preventDefault){ e.preventDefault();// }else{ window.event.returnValue = false;//IE //注意:這個地方是沒法用return false代替的 //return false只能取消元素 } }
二、return false javascript的return false只會阻止默認行爲,而是用jQuery的話則既阻止默認行爲又防止對象冒泡。
//原生js,只會阻止默認行爲,不會中止冒泡 var a = document.getElementById("testA"); a.onclick = function(){ return false;//固然 也阻止了事件自己 }; //既然return false 和 e.preventDefault()都是同樣的效果,那它們有區別嗎?固然有。 //僅僅是在HTML事件屬性 和 DOM0級事件處理方法中 才能經過返回 return false 的形式組織事件宿主的默認行爲。
1 //jQuery,既阻止默認行爲又中止冒泡 2 $("#testA").on('click',function(){ 3 return false;//固然 也阻止了事件自己 4 });
當須要中止冒泡行爲時
function stopBubble(e) { //若是提供了事件對象,則這是一個非IE瀏覽器 if ( e && e.stopPropagation ){ e.stopPropagation(); //所以它支持W3C的stopPropagation()方法 }else{ window.event.cancelBubble = true; //不然,咱們須要使用IE的方式來取消事件冒泡 } }
當須要阻止默認事件時
function stopDefault( e ) { if ( e && e.preventDefault ){ e.preventDefault(); //阻止默認瀏覽器動做(W3C) }else { window.event.returnValue = false; //IE中阻止函數器默認動做的方式 } return false; }
讓咱們回顧一下最初的問題,可能部分瀏覽器把事件的useCapture默認爲true,致使點擊子元素時父元素的事件先響應了,因而個人辦法是在父元素的事件裏進行判斷
好比容器爲
#a,
動態插入的元素爲#b,
在#a上監聽click事件,判斷event.target.id是否是等於b便可,若是.b
class這種,以此類推。
咱們常常能遇到阻止冒泡,可是阻止捕獲通常不會遇到,由於瀏覽器通常默認就給咱們阻止了,只能說什麼狀況都有啊,萬事仍是得考慮周全。