事宜流与事宜托付
事宜,即文档或浏览器中发作的一些特定交互的霎时,我们能够应用事宜监听来预定事宜,当事宜发作的时刻实行相应的处置惩罚递次。当事宜发作在某个DOM节点上时,事宜在DOM构造中举行一级一级的通报,这便形成了“流”,事宜流便形貌了从页面中吸收事宜的递次。本文重要议论事宜流的三个阶段,及应用事宜托付机制举行机能优化。
DOM事宜流
关于事宜流的明白,《JS高程三》中有个抽象的比方:
能够设想画在一张纸上的一组同心圆,假如你把手指放在圆心上,那末你的手指指向的实在不是一个圆,而是纸上一切的圆。…>换句话说,在单击按钮的同时,你也单击了按钮的容器元素,以至也单击了全部页面。
————《JavaScript高等递次设计(第三版)》page 345
DOM2级事宜中划定事宜流包括3个阶段:
捕捉阶段
处于目的阶段
冒泡阶段
起首发作的是事宜捕捉阶段,此时事宜还没有通报到目的节点对象上,所以我们就有时机在这个阶段举行事宜的截。然后是目的节点吸收到事宜,末了是事宜冒泡阶段,能够在这个阶段对事宜做出处置惩罚和相应。
我们先定义一段简朴的html构造:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div class="box">
<button type="button" name="button">click me</button>
</div>
</body>
</html>
事宜捕捉阶段
在事宜捕捉阶段中,先由不详细的节点(即上层节点)吸收到事宜,然后一级一级往下通报,直到最详细的目的节点
吸收到事宜。
在DOM2级事宜范例中,请求事宜从document
对象最先通报,然则诸如Chrome,Firefox等主流浏览器倒是从window
最先通报的。
addEventListener
要领的第三个参数是一个布尔值(可选),指定事宜处置惩罚递次是不是在捕捉或冒泡阶段实行。 当为true
时,则事宜处置惩罚递次将在捕捉阶段实行。误区:不管
addEventListener
的第三个参数是不是为true
,三个阶段都邑走一遍,这里的第三个参数,指的是处置惩罚递次将会在捕捉或许冒泡阶段实行,好比是你想买菜,你能够在上班路上,或许放工路上完成买菜,但不管什么时刻买菜,你都要把这两段旅程走完。
document.querySelector('#btn').addEventListener('click', function () {
console.log("btn was clicked");
},true);
document.querySelector('body').addEventListener('click', function () {
console.log("body was clicked");
},true);
document.querySelector('.box').addEventListener('click', function () {
console.log("box was clicked");
},true);
document.addEventListener('click', function () {
console.log("document was clicked");
},true);
window.addEventListener('click', function () {
console.log("window was clicked");
},true);
点击click me
按钮后,控制台顺次打印出实行效果:
window was clicked
document was clicked
body was clicked
box was clikced
btn was clicked
很明显能够看出,在捕捉阶段,事宜由window
对象最先,一级一级地向下通报,直到通报到最详细的button
对象上。
事宜冒泡阶段
事宜冒泡阶段与捕捉阶段恰好相反,冒泡阶段是从最详细的目的对象最先,一层一层地向上通报,直到window
对象。addEventListener
要领默许就是从冒泡阶段
实行事宜处置惩罚递次。
document.querySelector('#btn').addEventListener('click', function () {
console.log("btn was clicked");
});
document.querySelector('body').addEventListener('click', function () {
console.log("body was clicked");
});
document.querySelector('.box').addEventListener('click', function () {
console.log("box was clicked");
});
document.addEventListener('click', function () {
console.log("document was clicked");
});
window.addEventListener('click', function () {
console.log("window was clicked");
});
点击click me
按钮后,控制台顺次打印出实行效果:
btn was clicked
box was clikced
body was clicked
document was clicked
window was clicked
上述历程示意图:
阻挠事宜冒泡
我们能够运用event.stopPropagation()
要领阻挠事宜冒泡历程,以防备事宜冒泡而带来不必要的毛病和搅扰。
示例:
document.querySelector('#btn').addEventListener('click', function (event) {
console.log("btn was clicked");
event.stopPropagation();
});
document.querySelector('body').addEventListener('click', function () {
console.log("body was clicked");
});
document.querySelector('.box').addEventListener('click', function () {
console.log("box was clicked");
});
document.addEventListener('click', function () {
console.log("document was clicked");
});
window.addEventListener('click', function () {
console.log("window was clicked");
});
点击click me
按钮后,控制台打印出实行效果显现,事宜没有再向上冒泡通报给其他节点对象:
btn was clicked
事宜托付
每一个函数都是对象,都邑占用内存,所以当我们的页面中所包括的事宜数目较多时,假如给每一个节点绑定一个事宜,加上事宜处置惩罚递次,就会形成机能很差。另有一个题目是,某个元素节点是厥后经由过程JavaScript动态添加进页面中的,这时刻我们假如提早对它举行绑定,但此时该元素并不存在,所以会绑定事宜会失利。处理上述两个题目的一个经常使用计划,就是运用事宜托付
。
举例来说:
document.querySelector('.box').addEventListener(function (event) {
switch (event.target.id) {
case "btn":
console.log("btn was clicked");
break;
case "btn-2":
console.log("btn-2 was clicked");
break;
default:
console.log("box was clicked");
break;
}
});
$(".box").append("<button id='btn-2'>btn-2</button>");
简朴说,事宜托付就是把原本该本身吸收的事宜托付给本身的上级(父级,祖父级等等)的某个节点,让本身的“尊长们”帮助盯着,一旦有事宜触发,再由“尊长们”通知本身:“喂,孙子,有人找你~~”。
恩,差不多就是这么个意义,可怜天下父母心。
程度有限,迎接人人不吝指正。