一、事件委托
- 基于事件的冒泡传播机制完成
- 如果一个容器中很多元素都要在触发某一事件的时候做一些事情(原始方案:给元素的每一个都单独进行事件绑定),我们只需要给当前容器的这个事件行为绑定方法,这样不论是触发后代中哪一个元素的相关事件行为,由于冒泡传播机制,当前容器绑定的方法也都要被触发执行
- 想知道点击的是谁(根据是谁做不同的事情),只需要基于事件对象中的 ev.target 事件源获取既可。
- 基于事件委托实现,整体性能要比一个个的绑定方法高出50%左右
- 如果多元素触发,业务逻辑是属于一体的,基于事件委托来处理更加好
- 某些业务场景只能基于事件委托处理
- 在真实项目中,如果要操作的元素是基于 JS 动态绑定的,那么“相关事件行为触发做些事情”的处理操作,我们尽可能基于事件委托来处理(事件委托可以给动态绑定的元素绑定事件)
二、基于事件委托来实现某些功能
案例1
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>事件委托</title> <!-- IMPORT CSS --> <link rel="stylesheet" href="css/reset.min.css"> <style> .container { margin: 20px auto; width: 200px; } .container .box { box-sizing: border-box; float: right; width: 100px; height: 35px; line-height: 35px; text-align: center; font-size: 16px; border: 1px solid #AAA; position: relative; top: 1px; } .container .detail { display: none; box-sizing: border-box; float: right; width: 200px; height: 70px; line-height: 70px; text-align: center; font-size: 14px; border: 1px solid #AAA; } </style></head><body> <div class="container clearfix"> <div class="box"><span>购物车</span></div> <div class="detail"> 暂无购物车内容 </div> </div> <!-- IMPORT JS --> <script> let box = document.querySelector('.box'), detail = document.querySelector('.detail'); document.onmouseover = function (ev) { let target = ev.target; if (target.tagName === "SPAN") { // 如果事件源是 SPAN,我们让其变为其父元素 target = target.parentNode; } if (/^(box|detail)$/.test(target.className)) { // 如果事件源的 CLASS 是 BOX / DETAIL detail.style.display = 'block'; return; } detail.style.display = 'none'; } /* box.onmouseover = function (ev) { detail.style.display = 'block'; } box.onmouseout = function (ev) { detail.style.display = 'none'; } detail.onmouseover = function (ev) { detail.style.display = 'block'; } detail.onmouseout = function (ev) { detail.style.display = 'none'; } */ </script></body></html>
案例2
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>事件委托</title> <!-- IMPORT CSS --> <link rel="stylesheet" href="css/reset.min.css"> <style> .container { margin: 20px auto; width: 200px; } .container .box { box-sizing: border-box; float: right; width: 100px; height: 35px; line-height: 35px; text-align: center; font-size: 16px; border: 1px solid #AAA; position: relative; top: 1px; } .container .detail { display: none; box-sizing: border-box; float: right; width: 200px; height: 70px; line-height: 70px; text-align: center; font-size: 14px; border: 1px solid #AAA; } </style></head><body> <div class="container clearfix"> <div class="box"><span>购物车</span></div> <div class="detail"> 暂无购物车内容 </div> </div> <!-- IMPORT JS --> <script> let box = document.querySelector('.box'), detail = document.querySelector('.detail'); document.onclick = function (ev) { /* let target = ev.target; target.tagName === "SPAN" ? target = target.parentNode : null; if (/^box$/.test(target.className)) { // 如果是 BOX 让其显示 detail.style.display = 'block'; return; } */ /* if (/^detail$/.test(target.className)) { //=>如果是DETAIL啥也不干 return; } */ // 剩下的都是隐藏 detail.style.display = 'none'; } box.onclick = function (ev) { // 如果是 BOX 让其显示 detail.style.display = 'block'; ev.stopPropagation(); } detail.onclick = function (ev) { // 如果是 DETAIL 啥也不干 ev.stopPropagation(); } </script></body></html>
案例3
<!DOCTYPE html><html><head> <meta charset="UTF-8"> <title>事件委托</title> <!-- IMPORT CSS --> <link rel="stylesheet" href="css/reset.min.css"> <style> .box { margin: 20px auto; width: 200px; } .newsList { box-sizing: border-box; padding: 5px; border: 2px solid lightcoral; } .newsList li { line-height: 35px; border-bottom: 1px dashed #BBB; } .createBtn { box-sizing: border-box; margin-top: 10px; width: 80px; height: 30px; border: 1px solid #AAA; } </style></head><body> <div class="box"> <ul class="newsList"> <li>我是第1个LI</li> <li>我是第2个LI</li> <li>我是第3个LI</li> <li>我是第4个LI</li> <li>我是第5个LI</li> </ul> <button class="createBtn">新增</button> </div> <!-- IMPORT JS --> <script src="js/jquery.min.js"></script> <script> let $newsList = $('.newsList'), $createBtn = $('.createBtn'), count = 5; $newsList.click(function (ev) { let target = ev.target, $target = $(target); if (target.tagName === 'LI') { alert(`我是第${$target.index()+1}个LI`); } }); $createBtn.click(function () { let str = ``; for (let i = 0; i < 5; i++) { count++; str += `<li>我是第${count}个LI</li>`; } $newsList.append(str); }); </script> <script> /* let $newsList = $('.newsList'), $createBtn = $('.createBtn'), $lis = null; function handle() { $lis = $newsList.children('li'); $lis.each(function (index, item) { $(item).click(function () { alert(`我是第${index+1}个LI`); }); }); } handle(); let count = 5; $createBtn.click(function () { let str = ``; for (let i = 0; i < 5; i++) { count++; str += `<li>我是第${count}个LI</li>`; } $newsList.append(str); handle(); }); */ </script></body></html>
案例4
// 点击页面中的每个 li,输出每个 li 里面的内容let lis = document.querySelectorAll('#list > li');// for 循环 给每个 li 绑定一个点击事件for (let i = 0; i < lis.length; i++) { lis[i].onclick = function () { console.log(this.innerText); }}// 事件委托:当遇到对一个元素中的所有子元素绑定相同的事件,并且事件触发时做的事情一样;利用事件的冒泡机制,我们把事件绑定给父元素(一般绑定给父元素,也可以绑定给更高的元素),然后根据事件触发时 事件源 e.target 判断你点击的到底是哪个元素;let list = document.querySelector('#list');list.onclick = function (e) { // ?? 怎么知道你点击的哪个li呢? // e.target 是触发事件的目标元素; console.log(e.target.innerText);};// 事件委托的性能比循环绑定性能好;