浅谈js的事件冒泡和事件捕获

 

前言:javascript

   这篇文章起源于上次工做上的缘由,在事件上出的bug,因此就抽空写出一篇,也便于本身之后查阅,如如有幸被您阅读的话,小妹备感荣幸,文章仅为我的理解,若是内容有误的还望海涵,在您时间还方便的时候,但愿能告知小妹!谢谢!html

 

 什么是事件?java

   事件是文档和浏览器窗口中发生的特定的交互瞬间。 事件是javascript应用跳动的心脏,也是把全部东西黏在一块儿的胶水,当咱们与浏览器中web页面进行某些类型的交互时,事件就发生了。web

 事件多是用户在某些内容上的点击,鼠标通过某个特定元素或按下键盘上的某些按键,事件还多是web浏览器中发生的事情,好比说某个web页面加载完成,或者是用户滚动窗口或改变窗口大小。浏览器

 

什么是事件流:dom

   事件流描述的是从页面中接受事件的顺序,但有意思的是,微软(IE)和网景(Netscape)开发团队竟然提出了两个截然相反的事件流概念,IE的事件流是事件冒泡流(event bubbling)而Netscape的事件流是事件捕获流(event capturing)函数

   

 

 第一种:事件冒泡spa

       IE提出的事件流叫作事件冒泡,即事件开始时由最具体的元素接收,而后逐级向上传播到较为不具体的节点,看一下如下示例:code

<!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元素,看看会发生什么:htm

   正如上面咱们所说的,它会从一个最具体的的元素接收,而后逐级向上传播, p=>button=>div=>body..........事件冒泡能够形象地比喻为把一颗石头投入水中,泡泡会一直从水底冒出水面。

 

 第二种:事件捕获

         网景公司提出的事件流叫事件捕获流。

          事件捕获流的思想是不太具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件,针对上面一样的例子,点击按钮,那么此时click事件会按照这样传播:(下面咱们就借用addEventListener的第三个参数来模拟事件捕获流)

<!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>

一样咱们看一下后台的打印结果:

正如咱们看到的,和冒泡流万全相反,从最不具体的元素接收到最具体的元素接收事件  body=>div=>button=>p 

 

DOM事件流:

      ‘DOM2级事件’规定的事件流包含3个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。首先发生的事件捕获为截获事件提供机会,而后是实际的目标接收事件,最后一个阶段是事件冒泡阶段,能够在这个阶段对事件作出响应。

   在DOM事件流中,事件的目标在捕获阶段不会接收到事件,这意味着在捕获阶段事件从document到<p>就中止了,下个阶段是处于目标阶段,因而事件在<p>上发生,并在事件处理中被当作冒泡阶段的一部分,而后,冒泡阶段发生,事件又传播回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("div 处于目标阶段");
};
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>
 

看看后台给出什么结果:

就是这样一个流程,先捕获,而后处理,而后再冒泡出去。

 

 

 

 关于DOM 2级事件处理程序:

 

     DOM 2级事件定义了两方法:用于处理添加事件和删除事件的操做: 添加事件 addEventListener()     删除事件  removeEventListener()

   全部DOM节点中都包含这两个方法,而且他们都包含3个参数(1) 要处理的事件方式(例如:click,mouseover,dbclick.....) (2)事件处理的函数,能够为匿名函数,也能够为命名函数(但若是须要删除事件,必须是命名函数) (3)一个布尔值,表明是处于事件冒泡阶段处理仍是事件捕获阶段(true:表示在捕获阶段调用事件处理程序;false:表示在冒泡阶段调用事件处理程序)

  使用DOM 2级事件处理程序的主要好处是能够添加多个事件处理程序,事件处理会按照他们的顺序触发,经过addEventListener添加的事件只能用removeEventListener来移除,移除时传入的参数与添加时使用的参数必须相同,这也意味着添加的匿名函数将没法移除,(注意:咱们默认的第三个参数都是默认false,是指在冒泡阶段添加,大多数状况下,都是将事件处理程序添加到事件的冒泡阶段,这样能够最大限度的兼容各个浏览器

 

 

//这是一个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(2)
        }
        function newFoo(){
            console.log(9)
        }
    </script>
</body>
</html>

看一下结果:

只执行了第一个事件,第二个被忽略,这并非咱们想要的结果,而addEventLiener是会把两个事件都去执行的。

 

结尾:

   以上就是事件冒泡,事件捕获,dom事件流,dom2级事件流的全部内容,谢谢阅读!

相关文章
相关标签/搜索