一、事件冒泡和事件捕获的区别
-
事件冒泡和事件捕捉都是浏览器事件的传递机制
-
事件冒泡:当给父子元素的同一事件绑定方法的时候,触发子元素身上的事件,执行完毕之后,会触发父级元素相同的事件,就是触发的顺序是由DOM树的下层到DOM树的最上面,这种机制叫事件冒泡,取消事件冒泡可以用event.stopProPagation
-
事件捕获:事件捕获的思想是指不太具体的节点应该更早的接收到事件,而最具体的节点应该最后接收到事件,给父子元素用 addeventlistener()绑定同一事件时,并且第三个参数改为 true ,当触发子元素身上的事件时,先触发父元素,然后在传递给子元素,这种传播机制叫事件捕获
二、事件冒泡
<!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元素后
三、事件捕获
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<button>
<p>点击捕获</p>
</button>
</div>
<script>
var oP=document.querySelector('p');
var oB=document.querySelector('button');
var oD=document.querySelector('div');
var oBody=document.querySelector('body');
oP.addEventListener('click',function(){
console.log('p标签被点击')
},true);
oB.addEventListener('click',function(){
console.log("button被点击")
},true);
oD.addEventListener('click', function(){
console.log('div被点击')
},true);
oBody.addEventListener('click',function(){
console.log('body被点击')
},true);
</script>
</body>
</html>
复制代码
点击p元素后
四、DOM事件流
DOM2级事件规定的事件流包含3个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,然后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,可以在这个阶段对事件做出响应
而在DOM事件流中,事件的目标在捕获阶段不会接收到事件,这意味着在捕获阶段事件从document到<button>
就停止了,下个阶段是处于目标阶段,于是事件在<button>
上发生,并在事件处理中被看成冒泡阶段的一部分,然后,冒泡阶段发生,事件又传播回document
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn">DOM事件流</button>
<script>
var btn=document.getElementById("btn");
btn.onclick=function(event){
console.log("btn 处于目标阶段");
};
document.body.addEventListener("click",function(event){
console.log("event bubble 事件冒泡");
},false);
document.body.addEventListener("click",function(event){
console.log("event catch 事件捕获");
},true);
</script>
</body>
</html>
复制代码
打印的顺序分别是:
- event catch 事件捕获
- btn 处于目标阶段
- event bubble 事件冒泡
五、DOM 2级事件流
DOM 2级事件定义了两方法:用于处理添加事件和删除事件的操作:
- 添加事件 addEventListener()
- 删除事件 removeEventListener()
所有DOM节点中都包含这两个方法,并且他们都包含3个参数:
- 要处理的事件类型(例如:click,mouseover,dbclick…..)
- 事件处理的函数,可以为匿名函数,也可以为命名函数(但如果需要删除事件,必须是命名函数)
- 一个布尔值,代表是处于事件冒泡阶段处理还是事件捕获阶段处理(true:表示在捕获阶段调用事件处理程序;false:表示在冒泡阶段调用事件处理程序)
使用DOM 2级事件处理程序的主要好处是可以添加多个事件处理程序,事件处理会按照他们的顺序触发,通过 addEventListener 添加的事件只能用 removeEventListener 来移除,移除时传入的参数与添加时使用的参数必须相同,这也意味着添加的匿名函数将无法移除(注意:第三个参数都是默认false,是指在冒泡阶段处理事件,大多数情况下,都是将事件处理程序添加到事件的冒泡阶段,这样可以最大限度的兼容各个浏览器)
DOM 2级事件添加方式
//这是一个DOM 2级事件 添加事件最简单的方式(此时添加的是一个匿名函数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>按钮</button>
<script>
var btn=document.querySelector('button');
btn.addEventListener('click',function(){
console.log('我是按钮')
},false)
// 当第三个参数不写时,也是默认为false(冒泡阶段处理事件)
</script>
</body>
</html>
// 命名函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>按钮</button>
<script>
var btn=document.querySelector('button');
btn.addEventListener('click',foo,false);
function foo(){
console.log('我是按钮')
}
// 其实操作就是把写在里面的函数拿到了外面,而在原来的位置用函数名来代替
</script>
</body>
</html>
复制代码
- 添加两个事件时候的执行顺序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button>按钮</button>
<script>
var btn=document.querySelector('button');
// 第一个事件
btn.addEventListener('click',foo,false);
function foo(){
console.log('我是按钮')
}
//第二个事件
btn.addEventListener('click',newFoo,false);
function newFoo(){
console.log('我是新按钮')
}
</script>
</body>
</html>
复制代码
结论:添加两个事件是可以的,事件的顺序就是按照程序写的顺序执行的
- 试试DOM 0级事件处理程序
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button onclick="foo()" onclick="newFoo()">按钮</button>
<script>
function foo(){
console.log('我是按钮')
}
function newFoo(){
console.log('我是新按钮')
}
</script>
</body>
</html>
复制代码
后台只打印了“我是按钮”,说明DOM 0级事件处理程序只执行了第一个事件,第二个事件被忽略了