欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

事件流

程序员文章站 2022-05-07 17:23:46
文章目录前言一、以前两种事件流分析1.冒泡事件流2.捕获事件流结合:二、JS事件流1.原理1.on属性问题:2.addEventLIstener()问题三、阻止事件传递1.Event.stopPropagation() 方法2.Event.stopImmediatePropagation()方法3.cancelBubble前言JS事件流问题也可以理解为事件触发顺序问题,而JS事件流最早要从IE和网景公司的浏览器大战说起,当浏览器发展到第四代时,IE提出的是冒泡流,而网景提出的是捕获流,两种事件流形式...


前言

JS事件流问题也可以理解为事件触发顺序问题,而JS事件流最早要从IE和网景公司的浏览器大战说起,当浏览器发展到第四代时,IE提出的是冒泡流,而网景提出的是捕获流,两种事件流形式完全相反。


一、以前两种事件流分析

1.冒泡事件流

个人理解是和冒泡排序原理相似,即事件有最具体的接收,之后逐渐向上冒泡,传到页面。(即由子元素逐渐向父元素传)
以button按钮为例:

事件流

2.捕获事件流

与冒泡事件流原理完全相反,事件从页面元素开始接收,逐级向下到最具体的元素。
同样以button按钮为例:
事件流

结合:

后来在W3C组织的统一之下,JS支持了冒泡流和捕获流,两种事件流在DOM2级事件中得到了统一,相对于DOM0事件类型,DOM2级有以下特点:

  1. 允许某个元素绑定多个同类型事件(可以拿addEventLIstener事件与on事件为例)。
  2. 规定了事件流的三个阶段:捕获阶段,目标阶段,冒泡阶段。
    注意用Event.eventPhase可以返回当前所在的阶段:
var phase = event.eventPhase;

0,事件目前没有发生。
1,事件目前处于捕获阶段,即处于从祖先节点向目标节点的传播过程中。
2,事件到达目标节点,即Event.target属性指向的那个节点。
3,事件处于冒泡阶段,即处于从目标节点向祖先节点的反向传播过程中。


二、JS事件流

1.原理

JS事件的原理图如下:

事件流
由图可知:

  1. 现在的JS事件流是由捕获事件流和冒泡事件流组合形成的,即由window开始最后回到window的过程。
  2. 事件流被分为三个阶段(1-5)捕获过程、(5-6)目标过程、(6~10)冒泡过程。
  3. 这个过程决定了事件点击时的执行顺序。

1.on属性问题:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div style="width:200px;height:200px;background:lightblue" id="content">
        <button style="width:100px;height:50px;" id="btn1">
        </button>
    </div>
</body>
<script type="text/javascript">
    var content = document.getElementById("content");
    var btn1 = document.getElementById('btn1');
    btn1.onclick = function(){
        alert("button");
    };
    content.onclick = function(){
        alert("content");
    }
    //点击button的结果是先打印button之后再打印content
</script>
</html>

由执行结果可知,on-属性的执行是在冒泡阶段发生的,对于EventTarget.addEventListener()的原理也是一样的。

2.addEventLIstener()问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset = "UTF-8">
    <title>Document</title>
</head>
<body>
    <div style = "width:200px;height:200px;background:lightblue" id="content">
        <button style = "width:100px;height:50px;" id="btn1">
        </button>
    </div>
</body>
<script type = "text/javascript">
    var content = document.getElementById("content");
    var btn1 = document.getElementById('btn1');
   btn1.addEventListener('click', function () {  alert("button的冒泡阶段"); }, false);
   btn1.addEventListener('click', function () {  alert("button的捕获阶段"); }, true);
   content.addEventListener('click', function () {  alert('content的冒泡阶段'); }, false);
   content.addEventListener('click', function () {  alert('content的捕获阶段'); }, true);
   //结果为:content的捕获阶段
   //       button的冒泡阶段
   //        button的捕获阶段
   //        content的冒泡阶段
</script>
</html>

注意EventTarget.addEventListener()监听函数useCapture值为false时表示只在冒泡阶段被触发


三、阻止事件传递

通过之前的描述可以轻易看出,事件流中某元素被触发之后会造成连锁反应:会导致其容器元素同类型的事件被触发,有时候,这并不是我们所需要的所以,我们需要进行阻止。

1.Event.stopPropagation() 方法

stopPropagation()方法可以阻止事件在 DOM 中继续传播,防止再触发定义在别的节点上的监听函数,但是不包括在当前节点上其他的事件监听函数。
上代码:

function stopEvent(e) {
  e.stopPropagation();
}

el.addEventListener('click', stopEvent, false);

此时,click事件将不会进一步冒泡到el节点的父节点。

2.Event.stopImmediatePropagation()方法

此方法与之前的方法最大的区别在于其阻止的更加彻底,可以阻止同一个事件的其他监听函数被调用,不管监听函数定义在当前节点还是其他节点。
如果同一个节点对于同一个事件指定了多个监听函数,这些函数会根据添加的顺序依次调用。只要其中有一个监听函数调用了Event.stopImmediatePropagation()方法,其他的监听函数就不会再执行了。
上代码:

function l1(e){
  e.stopImmediatePropagation();
}

function l2(e){
  console.log('hello world');
}

el.addEventListener('click', l1, false);
el.addEventListener('click', l2, false);

上面代码在el节点上,为click事件添加了两个监听函数l1和l2。由于l1调用了event.stopImmediatePropagation方法,所以l2不会被调用。

3.cancelBubble

cancelBubble是IE标准下阻止事件传递的属性,设置cancelBubble=true表示阻止冒泡。
它与stopPropagation()兼容性对比如下:
事件流
所以,注意:

  1. 若需要在捕获阶段阻止事件传递,使用addEventListener()进行事件监听,同时使用e.stopPropagation()阻止冒泡。
  2. 若需要在冒泡阶段阻止事件传递,在兼容addEventListener()和attachEvent()的同时,为保险起见,需要对阻止事件传递方式进行兼容。以下仅表示在DOM2及事件模型下兼容方式:
if (e.stopPropagation){
      e.stopPropagation();
  }else{
      e.cancelBubble = true;
  }

本文地址:https://blog.csdn.net/qq_49042098/article/details/109385057