之前学习对DOM事件没有太注意,只知道 addEventListener
绑定,stopPropagation
停止冒泡,preventDefault
阻止默认事件。但对于更为细节的就不太清楚,于是便有了这篇笔记
绑定事件的方式
三种
/*
* 1
* 一个元素绑定两个处理函数,会覆盖
*/
elem.onclick = function(){}
/*
* 2
* 一个元素绑定两个处理函数,会覆盖
* false事件冒泡 true事件捕获
* ie9 以下不兼容,W3C 规范
* 同一个元素可以绑定多个事件
*/
elem.addEventListener(事件类型,事件处理函数,false)
/*
* 3
* ie8 及以下
* this` 指向 `window
*/
elem.attachEvent('onclick',function(){
test.call(elem);
})
function test(){} // 解决attachEvent 中this指向问题
解除绑定的方式
两种
elem.onclick = null / false
elem.removeEventListener() // 参数需要和绑定时候的参数完全相同
elem.addEventListener('click', function(){
this.className = '';
this.innerHTML = '';
this.removeEventListenner('click', arguments.callee, false); // 非严格模式下
})
捕获和冒泡
focus blur change submit reset select** **没有冒泡
怎么判断
elem.addEventListener(事件类型,事件处理函数,false) // false 代表冒泡 true 代表捕获
冒泡
事件开始时由最具体的元素接收 , 然后逐级向上传播到较为不具体的节点
捕获 不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件
DOM 事件流
事件流描述的是从页面中接受事件的顺序 业内有两种事件流的概念,分别是IE的冒泡流、网景的捕获流 IE:事件是由具体的DOM节点应该最早接收到事件,而最不具体的节点应该最后接收到事件 网景:事件开始时由最不具体的元素接收,然后逐级向下传播到具体的节点
冒泡流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body onclick="bodyClick()">
<div onclick="divClick()">
<button onclick="btn()">
<p onclick="p()">点击冒泡</p>
</button>
</div>
<script>
function p() {
console.log("p标签被点击");
}
function btn() {
console.log("button被点击");
}
function divClick(event) {
console.log("div被点击");
}
function bodyClick() {
console.log("body被点击");
}
</script>
</body>
</html>
/*
p标签被点击
button被点击
div被点击
body被点击
*/
捕获流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
.wrapper {
width: 150px;
height: 150px;
background-color: aqua;
}
.outer {
width: 100px;
height: 100px;
margin-left: 150px;
background-color: bisque;
}
.inner {
width: 75px;
height: 75px;
margin-left: 100px;
background-color: blueviolet;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="outer">
<div class="inner"></div>
</div>
</div>
<script>
var wrapper = document.getElementsByClassName("wrapper")[0];
var outer = document.getElementsByClassName("outer")[0];
var inner = document.getElementsByClassName("inner")[0];
wrapper.addEventListener(
"click",
function () {
console.log("wrapper-捕获");
},
true
);
outer.addEventListener(
"click",
function () {
console.log("outer-捕获");
},
true
);
inner.addEventListener(
"click",
function () {
console.log("inner-捕获");
},
true
);
</script>
</body>
</html>
/*
wrapper-捕获
outer-捕获
inner-捕获
*/
两种流同时存在
先执行捕获流、在执行冒泡流
- wrapper-捕获
- outer-捕获
- inner-捕获
- wrapper-冒泡
- outer-冒泡
- inner-冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style>
.wrapper {
width: 150px;
height: 150px;
background-color: aqua;
}
.outer {
width: 100px;
height: 100px;
margin-left: 150px;
background-color: bisque;
}
.inner {
width: 75px;
height: 75px;
margin-left: 100px;
background-color: blueviolet;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="outer">
<div class="inner"></div>
</div>
</div>
<script>
var wrapper = document.getElementsByClassName('wrapper')[0];
var outer = document.getElementsByClassName('outer')[0];
var inner = document.getElementsByClassName('inner')[0];
wrapper.addEventListener('click', function () {
console.log('wrapper-捕获');
}, true);
outer.addEventListener('click', function () {
console.log('outer-捕获');
}, true);
inner.addEventListener('click', function () {
console.log('inner-捕获');
}, true);
wrapper.addEventListener('click', function () {
console.log('wrapper-冒泡');
}, false);
outer.addEventListener('click', function () {
console.log('outer-冒泡');
}, false);
inner.addEventListener('click', function () {
console.log('inner-冒泡');
}, false);
</script>
</body>
</html>
当冒泡捕获同时存在时,也会先绑定捕获,在绑定冒泡,于是先执行捕获、在执行冒泡,这是由于DOM 2级事件规定
DOM 2级事件
规定的事件流包含3个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。这个意思就是DOM事件触发了(用onclick触发),先捕获,看看有没有父级DOM有相同的事件,DOM父级执行完后,到了目标阶段,然后再进行冒泡
总结
DOM事件的执行与捕获冒泡无关,真正影响其执行顺序的是绑定顺序,绑定的最早,最早执行; 绑定是由捕获流和冒泡流决定的,onClick
方式绑定默认是冒泡流,只有 addEventListener
设置为true才会捕获流
当冒泡捕获同时存在时,也会先绑定捕获,在绑定冒泡,于是先执行捕获、在执行冒泡