一、js 为dom绑定事件发生了什么?
- DOM2级事件规定事件分为三个阶段
事件捕获阶段 | 事件捕获定义了事件首先由最外层的元素(window)接收,然后才是下级元素 |
---|---|
处于目标阶段 | 捕获到当前绑定的dom元素 |
事件冒泡阶段 | 从当前捕获阶段线上冒泡到document元素 |
addEventListener 可选参数介绍:
capture: Boolean | 设置为true时,表示捕获阶段触发事件,设置为false时,冒泡阶段触发事件。 表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。 |
---|---|
once: Boolean | 表示 listener 在添加之后最多只调用一次。如果是 true, listener 会在其被调用之后自动移除。 |
passive: Boolean | 设置为true时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。 |
举例证实:冒泡阶段
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>js 为dom绑定事件发生了什么</title>
</head>
<body id="body">
<div id="div">
<section id="section">
<button id="button">button</button>
</section>
</div>
<script>
/**
* @methods target.addEventListener(type, listener[, options]);
* @type 表示监听事件类型的字符串。 浏览器事件参考: https://developer.mozilla.org/zh-CN/docs/Web/Events
* @options(可选) {capture:Boolean,once:Boolean,passive:Boolean}
*/
const button = getElId('button');
const section = getElId('section');
const div = getElId('div');
const body = getElId('body');
button.addEventListener('click', function () {
console.log(this.id);
}, { capture: false, once: false, passive: false });
section.addEventListener('click', function () {
console.log(this.id);
}, { capture: false, once: false, passive: false });
div.addEventListener('click', function () {
console.log(this.id);
}, { capture: false, once: false, passive: false });
body.addEventListener('click', function () {
console.log(this.id);
}, { capture: false, once: false, passive: false });
/**
* @dec 简单装饰着模式
* @param el
* @returns {Element}
*/
function getElId (el) {
return document.getElementById(el);
}
</script>
</body>
</html>
结果:上述执行输出的顺序 验证了冒泡阶段 button->section->div->body
举例证实:捕获阶段 (capture:true) 即可设置事件在不会阶段执行
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>js 为dom绑定事件发生了什么</title>
</head>
<body id="body">
<div id="div">
<section id="section">
<button id="button">button</button>
</section>
</div>
<script>
/**
* @methods target.addEventListener(type, listener[, options]);
* @type 表示监听事件类型的字符串。 浏览器事件参考: https://developer.mozilla.org/zh-CN/docs/Web/Events
* @options(可选) {capture:Boolean,once:Boolean,passive:Boolean}
*/
const button = getElId('button');
const section = getElId('section');
const div = getElId('div');
const body = getElId('body');
button.addEventListener('click', function () {
console.log(this.id);
}, { capture: true, once: false, passive: false });
section.addEventListener('click', function () {
console.log(this.id);
}, { capture: true, once: false, passive: false });
div.addEventListener('click', function () {
console.log(this.id);
}, { capture: true, once: false, passive: false });
body.addEventListener('click', function () {
console.log(this.id);
}, { capture: true, once: false, passive: false });
/**
* @dec 简单装饰着模式
* @param el
* @returns {Element}
*/
function getElId (el) {
return document.getElementById(el);
}
</script>
</body>
</html>
结果:上述执行输出的顺序 验证了捕获阶段 body->div->section->button
举例证实:捕获阶段 (once) 即可设置事件只会执行一次,类似于jQuery once
button.addEventListener('click', function () {
console.log(this.id);
}, { capture: true, once: false, passive: false });
结果:虽然当前button事件只是执行一次,但是捕获和冒泡阶段的事件还是正常执行的。
举例证实:js实现事件委托的方法
/**
* @methods target.addEventListener(type, listener[, options]);
* @type 表示监听事件类型的字符串。 浏览器事件参考: https://developer.mozilla.org/zh-CN/docs/Web/Events
* @options(可选) {capture:Boolean,once:Boolean,passive:Boolean}
*/
const body = getElId('body');
body.addEventListener('click', function (event) {
if (event.target.nodeName.toLowerCase() === 'button' || event.target.id === 'button') {
console.log(`将button事件委托给body成功执行`);
}
}, { capture: false, once: false, passive: false });
/**
* @dec 简单装饰着模式
* @param el
* @returns {Element}
*/
function getElId (el) {
return document.getElementById(el);
}