一、事件委托
- 基于事件的冒泡传播机制完成
- 如果一个容器中很多元素都要在触发某一事件的时候做一些事情(原始方案:给元素的每一个都单独进行事件绑定),我们只需要给当前容器的这个事件行为绑定方法,这样不论是触发后代中哪一个元素的相关事件行为,由于冒泡传播机制,当前容器绑定的方法也都要被触发执行
- 想知道点击的是谁(根据是谁做不同的事情),只需要基于事件对象中的 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);
};
// 事件委托的性能比循环绑定性能好;