聊聊事件冒泡与事件捕获

什么是事件?

  事件是文档和浏览器窗口中发生的特定的交互瞬间。

什么是事件流:

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

让我们先聊聊DOM0级事件与DOM2级事件

  • DOM0

直接通过 onclick写在html里面的事件, 比如:

在标签内写onclick事件

<input onclick="alert(1)" />

在JS写onlicke=function(){}函数

1 document.getElementById("myButton").onclick = function () {
2     alert(‘thanks‘);
3 }
  • DOM2

主流浏览器DOM2级事件是通过以下两个方法用于处理指定和删除事件处理程序的操作:

  1. 添加事件   addEvenetListener    ------   可以为元素添加多个事件处理程序,触发时会按照添加顺序依次调用。
  2. 删除事件   removeEventListener   -------   不能移除匿名添加的函数。

它们都有三个参数:

  1. 第一个参数是事件名(如click)。
  2. 第二个参数是事件处理程序函数。  可以为匿名函数,也可以为命名函数(但如果需要删除事件,必须是命名函数)
  3. 第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调用。

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

匿名函数

1 //这是一个DOM 2级事件 添加事件最简单的方式(此时添加的是一个匿名函数)
2     <button>按钮</button>
3     <script>
4         var btn=document.querySelector(‘button‘);
5         btn.addEventListener(‘click‘,function(){
6             console.log(‘我是按钮‘)
7         },false)   //当第三个参数不写时,也是默认为false(冒泡时添加事件)
8     </script>

命名函数

1     <button>按钮</button>
2     <script>
3         var btn=document.querySelector(‘button‘);
4         btn.addEventListener(‘click‘,foo,false);
5         function foo(){
6             console.log(‘我是按钮‘)
7         }
8            //其实操作就是把写在里面的函数拿到了外面,而在原来的位置用函数名来代替
9     </script>


看完以上的,我们再了解事件冒泡与捕获



第一种(事件冒泡)IE提出

IE提出的事件流叫做事件冒泡,即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body onclick="bodyClick()">
 8
 9     <div onclick="divClick()">
10         <button onclick="btn()">
11             <p onclick="p()">点击冒泡</p>
12         </button>
13     </div>
14     <script>
15
16        function p(){
17           console.log(‘p标签被点击‘)
18        }
19         function btn(){
20             console.log("button被点击")
21         }
22          function divClick(event){
23              console.log(‘div被点击‘);
24          }
25         function bodyClick(){
26             console.log(‘body被点击‘)
27         }
28
29     </script>
30
31 </body>
32 </html>

接下来我们点击一下页面上的p元素,如下所示

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



第二种(事件捕获)网景提出

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

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8
 9 <div>
10     <button>
11         <p>点击捕获</p>
12     </button>
13 </div>
14 <script>
15     var oP=document.querySelector(‘p‘);
16     var oB=document.querySelector(‘button‘);
17     var oD=document.querySelector(‘div‘);
18     var oBody=document.querySelector(‘body‘);
19
20     oP.addEventListener(‘click‘,function(){
21         console.log(‘p标签被点击‘)
22     },true);
23
24     oB.addEventListener(‘click‘,function(){
25         console.log("button被点击")
26     },true);
27
28     oD.addEventListener(‘click‘,  function(){
29         console.log(‘div被点击‘)
30     },true);
31
32     oBody.addEventListener(‘click‘,function(){
33         console.log(‘body被点击‘)
34     },true);
35
36 </script>
37 </body>
38 </html>

同样我们看一下后台的打印结果

和冒泡流完全相反,从最不具体的元素接收到最具体的元素接收事件  body=>div=>button=>p 


  • 事件代理

在实际的开发当中,利用事件流的特性,我们可以使用一种叫做事件代理的方法。

<ul id="color-list">
    <li>red</li>
    <li>yellow</li>
    <li>blue</li>
    <li>green</li>
    <li>black</li>
    <li>white</li>
</ul>

如果点击页面中的li元素,然后输出li当中的颜色,我们通常会这样写:

1 var list_li = document.getElementsByTagName(‘li‘);
2 for (var i = 0; i < list_li.length; i++) {
3     list_li[i].addEventListener(‘click‘,foo,false);
4 }
5 function foo (e) {
6    let x = e.target;
7    console.log(x.innerHTML)
8 }

利用事件流的特性,我们只绑定一个事件处理函数也可以完成:

1 var list_ul = document.getElementById(‘color-list‘);
2 list_ul.addEventListener(‘click‘, foo, false);
3 function foo (e) {
4     let x = e.target;
5     if (x.nodeName == ‘LI‘) {
6       console.log(x.innerHTML)
7     }
8 }

  • 冒泡还是捕获?

    对于事件代理来说,在事件捕获或者事件冒泡阶段处理并没有明显的优劣之分,但是由于事件冒泡的事件流模型被所有主流的浏览器兼容,从兼容性角度来说还是建议大家使用事件冒泡模型。

  IE浏览器兼容

   IE浏览器对addEventListener兼容性并不算太好,只有IE9以上可以使用。

   要兼容旧版本的IE浏览器,可以使用IE的attachEvent函数

object.attachEvent(event, function)

   两个参数与addEventListener相似,分别是事件和处理函数,默认是事件冒泡阶段调用处理函数。并且由于IE浏览器只支持事件冒泡,所以添加的程序都被添加到冒泡阶段。要注意的是,写事件名时候要加上"on"前缀("onload"、"onclick"等)。

 区别

  addEventListener与attachEvent除了参数个数以及第一个参数意义不同外。还有如下两点:

  1. 事件处理程序的作用域不相同:addEventListener的作用域是元素本身,this指的是触发元素。而attachEvent事件处理程序会在全局变量内运行,this指的是window,所以刚才的例子返回的结果是undefined,而不是元素id。
  2. 为一个事件添加多个事件处理程序时,执行顺序不同:使用addEventListener时浏览器会按照添加顺序执行,IE浏览器使用attachEvent时,如果添加的方法过多时,IE浏览器将不会按照顺序执行。

  • 阻止事件冒泡与阻止默认事件

  阻止事件冒泡   stopPropagation() 方法

  可以阻止事件冒泡,也可以阻止事件捕获,也可以阻止处于目标阶段

  使用stopPaopagation()方法可以停止事件在DOM层次的传播,不再派发事件。

 1 <div id="p">parent
 2       <div id="c">child</div>
 3 </div>
 4 <script type="text/javascript">
 5 var p = document.getElementById(‘p‘),
 6       c = document.getElementById(‘c‘);
 7       c.addEventListener(‘click‘, function (e) {
 8       e.stopPropagation()
 9            alert(‘子节点冒泡‘)   //不再向上冒泡到父级
10 }, false);
11 p.addEventListener(‘click‘, function () {
12          alert(‘父节点冒泡‘)}, false);
13 </script>

  阻止默认事件   event.preventDefault() 方法   (基本没作用吧...很少有需求将默认事件取消掉吧)

event.preventDefault()

原文地址:https://www.cnblogs.com/cz976230/p/10659443.html

时间: 2024-08-01 15:37:36

聊聊事件冒泡与事件捕获的相关文章

JS事件(事件冒泡和事件捕获)

事件流:描述的是在页面中接收事件的顺序 事件冒泡:由最具体的元素接收,然后逐级向上传播至最不具体的元素的节点(文档) 事件捕获:最不具体的节点先接收事件,而最具体的节点应该是最后接收事件 DOM中:用于处理指定和删除事件处理程序的操作addEventListener()和removeEventListener().他们都接收三个参数:要处理的事件名.作为事件处理程序的函数和布尔值(事件处理的时候)[true:事件捕获时;false:事件冒泡时] DOM中的事件对象: type属性 用于获取事件类

看懂此文,不再困惑于javascript中的事件绑定、事件冒泡、事件捕获和事件执行顺序

最近一个项目基于3维skyline平台,进行javascript二次开发.对skyline事件的设计真是无语至极,不堪折磨啊!抽空学习了下javascript和jquery的事件设计,收获颇大,总结此贴,和大家分享. (一)事件绑定的几种方式 javascript给DOM绑定事件处理函数总的来说有2种方式:在html文档中绑定.在js代码中绑定.下面的方式1.方式2属于在html中绑定事件,方式3.方式4和方式5属于在js代码中绑定事件,其中方法5是最推荐的做法. 方式1: HTML的DOM元素

javascript事件之: 事件冒泡, 事件捕获 ,阻止默认事件

谈起JavaScript的 事件,事件冒泡.事件捕获.阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免. 冒泡篇: 先来看一段实例: js: var $input = document.getElementsByTagName("input")[0]; var $div = document.getElementsByTagName("div")[0]; var $body = document.getElementsByTagName("

javascript中的事件冒泡、事件捕获和事件执行顺序

谈起JavaScript的 事件,事件冒泡.事件捕获.阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免. DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有着相当大的影响.这两种事件流分别是捕获和冒泡.和许多Web技术一样,在它们成为标准之前,Netscape和微软各自不同地实现了它们.Netscape选择实现了捕获事件流,微软则实现了冒泡事件流.幸运的是,W3C决定组合使用这两种方法,并且大多数新浏览器都遵循这两种事件流方式. 1事件传播--冒泡与捕

事件冒泡和事件捕获

1.什么是事件冒泡 在页面上可以有多个事件,也可以多个元素响应同一个事件.假设页面上有两个元素,其中一个元素嵌套在另一个元素里,并且都被绑定了click事件,同时<body>元素也绑定了click事件,完整代码如下: <script> $(function(){ //为span元素绑定click事件 $("span").bind("click",function(){ var txt=$("#msg").html()+&q

js 事件冒泡与事件捕获

一.事件冒泡 事件冒泡是指在事件发生过程中先从目标节点开始执行,并一层一层的相父节点依次查询直到document,并执行相同事件的过程. btn1.addEventListener('click',function(e){ //true 为事件捕获,false 为事件冒泡 //false为默认方式,冒泡方式执行 //点击btn1时,如果是事件冒泡,则先执行btn1上的click事件,然后执行父元素div1上的click事件 //如果是事件捕获,则先执行父元素上的click事件,然后执行btn1上

前端-【学习心得】-聊一聊事件冒泡和事件捕获

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title>Examples</title> <meta name="description" conte

JS中的事件绑定,事件捕获,事件冒泡以及事件委托,兼容IE

转载请注明出处:http://www.cnblogs.com/zhangmingze/p/4864367.html ● 事件分为三个阶段:   事件捕获 -->  事件目标 -->  事件冒泡 ● 事件捕获:事件发生时(onclick,onmouseover--)首先发生在document上,然后依次传递给body.……最后到达目的节点(即事件目标). ● 事件冒泡:事件到达事件目标之后不会结束,会逐层向上冒泡,直至document对象,跟事件捕获相反 1.onlick -->事件冒泡,

JavaScript 进阶教程一 JavaScript 中的事件流 - 事件冒泡和事件捕获

先看下面的示例代码: <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>JavaScript 中的事件冒泡与事件捕获</title> </head> <body> <div id="Red" style="width:200px;height:200px;background-color:red;padding:2