事件冒泡
如下代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#div1 {
height: 300px;
width: 300px;
background-color: red;
}
#div2 {
height: 200px;
width: 200px;
background-color: black;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2"></div>
</div>
<script>
var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
div1.addEventListener('click', function () {
console.log('div1')
}, false);
div2.addEventListener('click', function () {
console.log('div2')
}, false);
</script>
</body>
</html>
将上述代码在浏览器打开,当点击div2(黑色)元素,会执行其回调函数打印文字div2,同时也会触发元素div1的回调函数,打印文字div1。即在冒泡状态下子元素的点击状态会传递给父元素,一直传递到document对象,这就是事件冒泡。因此上述的点击状态传递过程为:
div2->div1->body->html->document 由内而外传播
在addEventListener中,第一个参数时事件,第二个参数时回调函数,第三个参数是决定回调函数执行的环境,默认为false(在事件冒泡时执行回调函数)。
事件捕捉
事件捕捉与事件冒泡正好相反,只需要将上述事件冒泡代码两个监听器中第三个参数改为true即可,true代表回调函数在事件捕捉时执行。
改为true之后,点击状态的传递变为如下:
div1->div2 由外而内传播
事件代理(事件委托)
事件代理其实就是利用事件冒泡的原理,进行一些复杂操作的简化。如下代码:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
如果要对ul列表中所有li挂载事件,你可以手动写多个监听器去监听每一个li。当你在点击某一个li的时候,他的点击状态也会根据事件冒泡原理传递到ul中,我们可以根据这个原理,将所有li的事件都委托给ul,即将所有li的监听器只需要挂载在ul一个元素上即可,这样也能实现相同的效果。如下代码:
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<script>
var ul = document.getElementsByTagName('ul')[0];
ul.addEventListener('click' , function(){
console.log('点击了')
})
</script>
</body>
阻止事件冒泡和默认事件
先看没有阻止事件冒泡和默认事件的代码:
<body>
<ul id="ul1">
<li id="li1">1</li>
</ul>
<a href="http://www.baidu.com" id="a">百度</a>
<script>
var ul = document.getElementById('ul1')
var li = document.getElementById('li1');
var a = document.getElementById('a');
a.addEventListener('click' , function(){
console.log('a被点击了')
})
ul.addEventListener('click' , function(){
console.log('ul被点击了')
})
li.addEventListener('click' ,function(){
console.log('li被点击了');
})
</script>
</body>
此代码大家可以运行一下查看效果,完全点击li会触发li和ul的回调函数,点击a标签会发生跳转。
下面我们来看一下设置阻止事件冒泡和阻止默认事件的代码:
<body>
<ul id="ul1">
<li id="li1">1</li>
</ul>
<a href="http://www.baidu.com" id="a">百度</a>
<script>
var ul = document.getElementById('ul1')
var li = document.getElementById('li1');
var a = document.getElementById('a');
a.addEventListener('click' , function(e){
e.preventDefault()
console.log('a被点击了')
})
ul.addEventListener('click' , function(){
console.log('ul被点击了')
})
li.addEventListener('click' ,function(e){
console.log('li被点击了');
e.stopPropagation()
})
</script>
</body>
其中我们在a标签的回调函数中接收事件回调函数并且获取事件参数e,调用e的preventDefault方法可以将a标签的调转行为取消。
其中我们在li标签的回调函数中接收事件回调函数并且获取事件参数e,调用e的stopPropagation函数可以将li的点击冒泡状态取消。
综上,做以下总结:
preventDefault() 取消默认事件 比如a标签、submit按钮
stopPropagation() 取消事件冒泡