详解浏览器事件捕获、冒泡
目錄
事件委托/事件代理
包含幾個階段?
代碼演示
addEventListener第三個參數(shù)
e.target.nodeName 和 e.currentTarget.nodeName 區(qū)別
如何阻止事件的傳播?
現(xiàn)在有一個場景面試題
阻止事件默認行為
兼容性
封裝一個監(jiān)聽的方法
封裝一個阻止事件的傳播的方法
封裝一個阻止事件默認行為的方法
事件委托/事件代理
包含幾個階段?
三個階段:捕獲階段 => 目標階段 => 冒泡階段
捕獲階段:
 從上到下,從window到你點擊的目標節(jié)點,不如點擊一個 input
 window?=> body?=> inpiut?=> body?=> window
代碼演示
 ?
 
<body><div id="parent" class="flex-center">parent<p id="child" class="flex-center">child<span id="son" class="flex-center"><a id="aTag" href="https://baidu.com">點我啊</a></span></p></div>
</body>
<script type="text/javascript">const parent = document.getElementById('parent');
const child = document.getElementById('child');
const son = document.getElementById('son');
const aTag = document.getElementById('aTag');aTag.addEventListener('click', function(e) {e.preventDefault();    // 阻止A標簽?zāi)J事件
})window.addEventListener('click', function(e) {// e.target.nodeName 和 e.currentTarget.nodeName 下面會講這兩個參數(shù)的意思console.log('window 捕獲', e.target.nodeName, e.currentTarget.nodeName);
}, true); 
// addEventListener第三個參數(shù) true代表在捕獲階段執(zhí)行。false或者不填代表在冒泡階段執(zhí)行。parent.addEventListener('click', function(e) {console.log('parent 捕獲', e.target.nodeName, e.currentTarget.nodeName);
}, true);child.addEventListener('click', function(e) {console.log('child 捕獲', e.target.nodeName, e.currentTarget.nodeName);
}, true);son.addEventListener('click', function(e) {console.log('son 捕獲', e.target.nodeName, e.currentTarget.nodeName);
}, true);son.addEventListener('click', function(e) {console.log('son 冒泡', e.target.nodeName, e.currentTarget.nodeName);
}, false);child.addEventListener('click', function(e) {console.log('child 冒泡', e.target.nodeName, e.currentTarget.nodeName);
}, false);parent.addEventListener('click', function(e) {console.log('parent 冒泡', e.target.nodeName, e.currentTarget.nodeName);
}, false);window.addEventListener('click', function(e) {console.log('window 冒泡', e.target.nodeName, e.currentTarget.nodeName);
}, false);
</script>
 
效果如下:
點擊span標簽時控制臺輸出信息如下:
addEventListener第三個參數(shù)
- 默認值為冒泡
- true:代表在捕獲階段執(zhí)行
- false或者不填:代表在冒泡階段執(zhí)行
e.target.nodeName 和 e.currentTarget.nodeName 區(qū)別
- e.target.nodeName:指當前點擊的元素
- e.currentTarget.nodeName: 綁定事件監(jiān)聽的元素
如何阻止事件的傳播?
e.stopPropagation();注意:它不是阻止冒泡,而是阻止的事件的傳播!!!事件的捕獲和冒泡都會阻止掉!!!
 在以上代碼的監(jiān)聽 parent 點擊事件中加入?e.stopPropagation(); 會發(fā)生什么?
點擊span標簽時控制臺輸出信息如下:
我們在監(jiān)聽 parent 點擊事件中加入?e.stopPropagation(); 阻止了事件傳播,走到 parent 事件時,當前事件已經(jīng)觸發(fā)了所以會打印出? 「parent 捕獲 SPAN DIV」,但是會阻止后續(xù)事件的傳播。
如果在冒泡事件里面阻止事件的傳播呢?
child.addEventListener('click', function(e) {e.stopPropagation();console.log('child 冒泡', e.target.nodeName, e.currentTarget.nodeName); }, false);捕獲階段沒做攔截,整個捕獲階段會完整的走完,但是冒泡階段到了child就會走完,因為我們在child里面攔截了它。
現(xiàn)在有一個場景面試題
問題:現(xiàn)在有一個頁面,這個頁面上有許多的元素,div p button 等,每個元素上都有自己的 click 事件,都不相同。
 需求:一個用戶進入這個頁面的時候,會有一個狀態(tài) banned,window.banned 。
 true:表示當前用戶被封禁了,用戶點擊當點頁面上的任何元素,都不執(zhí)行原有的click邏輯,而是 alert 彈窗,提示你被封禁了!!!
false:不做任何操作
答:在最上層捕獲事件中做攔截,比如window,如果banned為true,就直接在捕獲階段阻止事件傳播,并且彈窗提示,否則不進行任何操作。
window.addEventListener('click', function(e) {if(banned) {e.stopPropagation();alert('你被封禁了!!!');return} console.log('window 捕獲', e.target.nodeName, e.currentTarget.nodeName); }, true);效果:當banned為true時,控制臺不會打印任何信息,會彈窗提示。未false?則不做任何操作;
阻止事件默認行為
e.preventDefault();
什么叫做默認行為
比如點擊a標簽會跳轉(zhuǎn)到另個頁面,比如拖拽到一張圖片到瀏覽器,瀏覽器會打開這個圖片,比如點擊表單提交按鈕,會提交當前表單……
如果我們不希望這些默認行為的發(fā)生,我們應(yīng)該怎么做?
最開始寫的代碼中有個a標簽,點擊時是要跳轉(zhuǎn)到百度的
<a id="aTag" href="https://baidu.com">點我啊</a>如果我們不想讓他跳轉(zhuǎn)到百度,在a標簽事件上做個攔截,當點擊 a標簽時,就不會跳轉(zhuǎn)到百度。
const aTag = document.getElementById('aTag');aTag.addEventListener('click', function(e) {e.preventDefault(); // 阻止a標簽?zāi)J事件 })兼容性
| addEventListener | 只支持 Firefox、Chrome、IE高版本、Safari、Opera | 
| attachEvent | 兼容IE7、IE8 | 
封裝一個監(jiān)聽的方法
? ? ? ? 我們很難真正的去一個元素上加一個方法之類的,那樣要去操作原型鏈,先簡單通過一個類的方式去封裝。
class BomEvent {constructor(element) {this.element = element;}/*** @param { 事件類型 } type * @param { 事件觸發(fā)后的回調(diào) } handler */addEvent(type, handler) { /*** 通過if判斷* 分別判斷 addEventListener、attachEvent、以及不存在它們的情況下去怎么做*/if(this.element.addEventListener) {/* 走冒泡形式,因為IE不支持事件的捕獲 */this.element.addEventListener(type, handler, false); } else if(this.element.attachEvent) {this.element.attachEvent(`on${type}`, handler)/*** 如果在attachEvent情況下考慮 IE7、IE8不支持箭頭函數(shù)的情況下* 把handler換成* function() { handler.call(element) };*/} else {/*** 可能有一些更奇怪的瀏覽器,attachEvent 都沒有* 我們直接給element上面綁定元素* 直接在 handler屬性上去綁*/this.element[`on${type}`] = handler;}}/*** 和 addEvent幾乎是一樣的* 只不過調(diào)用的API不同*/removeEvent(type, handler) {if(this.element.removeEventListener) {this.element.removeEventListener(type, handler, false); } else if(this.element.detachEvent) {this.element.detachEvent(`on${type}`, handler)} else {this.element[`on${type}`] = null;}} }封裝一個阻止事件的傳播的方法
function stopPropagation(event) {if(event.stopPropagation) {event.stopPropagation(); // 標準 w3c瀏覽器} else {event.cancelBubble = true; // IE} }封裝一個阻止事件默認行為的方法
function preventDefault(event) {if(event.preventDefault) {event.preventDefault(); // 標準 w3c瀏覽器} else {event.returnValue = false; // IE} }總結(jié)
以上是生活随笔為你收集整理的详解浏览器事件捕获、冒泡的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: usaco training 4.4.1
- 下一篇: 计算机视觉 专业术语,计算机视觉常用术语
