当点击一个按钮,事实上你还同时点击了按钮所有的父元素。事件流所描述的就是从页面中接受事件的顺序。因为有两种观点,所以事件流也有两种,分别是事件冒泡和事件捕获。现行的主流是事件冒泡。
事件冒泡
事件冒泡即事件开始时,由最具体的元素接收(也就是事件发生所在的节点),然后逐级传播到较为不具体的节点。
简述事件冒泡流程
- DOM树形结构
- 事件冒泡
- 阻止冒泡
- 冒泡的应用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Event Bubbling</title>
</head>
<body>
<button id="clickMe">Click Me</button>
</body>
</html>
var button = document.getElementById('clickMe');
button.onclick = function() {
console.log('1. You click Button');
};
document.body.onclick = function() {
console.log('2. You click body');
};
document.onclick = function() {
console.log('3. You click document');
};
window.onclick = function() {
console.log('4. You click window');
};
如果点击了button,那么这个点击事件会按如下的顺序传播:button>body>document>window
事件捕获的过程相反。
DOM事件流
DOM事件流包括三个阶段。
事件捕获阶段
处于目标阶段
事件冒泡阶段
addEventListener最后一个参数,为true则代表使用事件捕获模式,false则表示使用事件冒泡模式。
用事件冒泡实现代理
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<a href="#">a4</a>
</div>
var div1=document.getElementById('div1');
div1.addEventListener('click', function(e){
var target=e.target;
if(target.nodeName==='A'){
alert(target.innerHTML);
}
})
完善通用绑定事件的函数
function bindEvent(elem,type,selector,fn){
if(fn==null){
fn=selector
selector=null
}
elem.addEventListener(type, function(e){
var target
if(selector){
target=e.target
if(target.matches(selector)){
fn.call(target, e)
}
} else {
fn(e)
}
})
}
// 使用代理
var div1=document.getElementById('div1');
bindEvent(div1,'click','a',function (e) {
console.log(this.innerHTML)
})
// 不使用代理
var a=document.getElementById('a1');
bindEvent(div1,'click',function(e){
console.log(a.innerHTML);
})
代理的好处
减少浏览器内存占用
代码整洁