事件捕获、事件冒泡和事件委托
事件捕获和事件冒泡
事件捕获和事件冒泡是浏览器处理事件的两种顺序,IE9之前IE只有事件冒泡,IE9+、Chrome、火狐等两者皆有。
事件捕获是从根元素往下找,直到找到事件触发的真正DOM元素,因此事件触发顺序为外层事件到内层事件。
事件冒泡是从实际触发事件的元素出发,事件向外层元素冒泡,直到根元素,因此事件触发顺序为内层事件到外层事件。
支持两者的浏览器处理顺序为:
优先查找事件捕获,若注册了捕获事件,则从最外层开始触发;
事件捕获完成后,找到触发事件的最内层元素,向外进行事件冒泡
默认:事件冒泡
点击div4,未注册捕获事件,因此处理顺序为触发事件的最内层向外冒泡,弹出顺序为div4,div3,div2,div1
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>默认情况-事件冒泡</title> <style> #div1 { width: 400px; height: 400px; background-color: red; } #div2 { width: 300px; height: 300px; background-color: blue; } #div3 { width: 200px; height: 200px; background-color:green; } #div4 { width: 100px; height: 100px; background-color: gold; } .right-bottom { display: flex; justify-content: flex-end; align-items: flex-end; } </style> </head> <body> <div id="div1" class="right-bottom"> <div id="div2" class="right-bottom"> <div id="div3" class="right-bottom"> <div id="div4"></div> </div> </div> </div> <script> var div1 = document.querySelector('#div1'), div2 = document.querySelector('#div2'), div3 = document.querySelector('#div3'), div4 = document.querySelector('#div4'); div1.addEventListener('click', function(event) { alert(event.currentTarget.id) }) div2.addEventListener('click', function(event) { alert(event.currentTarget.id) }) div3.addEventListener('click', function(event) { alert(event.currentTarget.id) }) div4.addEventListener('click', function(event) { alert(event.currentTarget.id) }) </script> </body> </html>
修改为事件捕获:
点击div4,都注册了捕获事件,从最外层开始捕获触发事件,因此弹出顺序为div1,div2,div3,div4
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>自定义-事件捕获</title> <style> #div1 { width: 400px; height: 400px; background-color: red; } #div2 { width: 300px; height: 300px; background-color: blue; } #div3 { width: 200px; height: 200px; background-color:green; } #div4 { width: 100px; height: 100px; background-color: gold; } .right-bottom { display: flex; justify-content: flex-end; align-items: flex-end; } </style> </head> <body> <div id="div1" class="right-bottom"> <div id="div2" class="right-bottom"> <div id="div3" class="right-bottom"> <div id="div4"></div> </div> </div> </div> <script> var div1 = document.querySelector('#div1'), div2 = document.querySelector('#div2'), div3 = document.querySelector('#div3'), div4 = document.querySelector('#div4'); div1.addEventListener('click', function(event) { alert(event.currentTarget.id) }, true) div2.addEventListener('click', function(event) { alert(event.currentTarget.id) }, true) div3.addEventListener('click', function(event) { alert(event.currentTarget.id) }, true) div4.addEventListener('click', function(event) { alert(event.currentTarget.id) }, true) </script> </body> </html>
混合事件捕获和事件冒泡:
给div1和div3加上事件捕获,则点击div4,先从外层向内层进行事件捕获的触发,先弹出div1,div3,然后进入触发事件的最内层元素,开始进行事件冒泡,再弹出div4,div2,因此触发顺序为div1,div3,div4,div2
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>混合事件捕获和事件冒泡</title> <style> #div1 { width: 400px; height: 400px; background-color: red; } #div2 { width: 300px; height: 300px; background-color: blue; } #div3 { width: 200px; height: 200px; background-color:green; } #div4 { width: 100px; height: 100px; background-color: gold; } .right-bottom { display: flex; justify-content: flex-end; align-items: flex-end; } </style> </head> <body> <div id="div1" class="right-bottom"> <div id="div2" class="right-bottom"> <div id="div3" class="right-bottom"> <div id="div4"></div> </div> </div> </div> <script> var div1 = document.querySelector('#div1'), div2 = document.querySelector('#div2'), div3 = document.querySelector('#div3'), div4 = document.querySelector('#div4'); div1.addEventListener('click', function(event) { alert(event.currentTarget.id) }, true) div2.addEventListener('click', function(event) { alert(event.currentTarget.id) }) div3.addEventListener('click', function(event) { alert(event.currentTarget.id) }, true) div4.addEventListener('click', function(event) { alert(event.currentTarget.id) }) </script> </body> </html>
事件委托
事件委托是利用事件冒泡的原理,将子元素触发的事件冒泡到父元素进行处理,从而无需进行大量子元素的事件绑定,同时子元素动态变化时也无需重新绑定事件,因此大大提高了效率,优化了处理的方法。
例子:列表项鼠标悬停时字体变红,点击按钮可新增一个列表项
不使用事件委托的方式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>不使用事件委托的例子</title> </head> <body> <ul> <li>111111</li> <li>222222</li> <li>333333</li> </ul> <button id="add-item-btn">新增列表项</button> <script> var lis = document.querySelectorAll('li') lis.forEach(function(item) { item.addEventListener('mouseover', function() { item.style.color = 'red' }) item.addEventListener('mouseout', function() { item.style.color = 'black' }) }) var btn = document.querySelector('#add-item-btn') var ul = document.querySelector('ul'); btn.addEventListener('click', function() { var item = document.createElement('li') item.innerText = '444444' /*需要重新绑定事件*/ item.addEventListener('mouseover', function() { item.style.color = 'red' }) item.addEventListener('mouseout', function() { item.style.color = 'black' }) ul.appendChild(item) }) </script> </body> </html>
使用事件委托的方式:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>使用事件委托的例子</title> </head> <body> <ul> <li>111111</li> <li>222222</li> <li>333333</li> </ul> <button id="add-item-btn">新增列表项</button> <script> var btn = document.querySelector('#add-item-btn') var ul = document.querySelector('ul'); ul.addEventListener('mouseover', function(event) { if (event.target.tagName.toUpperCase() === 'LI') { event.target.style.color = 'red' } }) ul.addEventListener('mouseout', function(event) { if (event.target.tagName.toUpperCase() === 'LI') { event.target.style.color = 'black' } }) btn.addEventListener('click', function() { var item = document.createElement('li') item.innerText = '444444' /*不需要重新绑定事件*/ ul.appendChild(item) }) </script> </body> </html>
事件委托的方式代码简单,效率较高~
点赞4
支持一下