• 浅谈js之事件流


    这些日子我就把js的相关知识梳理一下,今天来说javascript中的事件流。

    1.事件流

    事件流:从页面中接收事件的顺序。也就是说当一个事件产生时,这个事件的传播过程,就是事件流。

    • IE的事件流

      IE中的事件流叫事件冒泡;事件冒泡:事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点(文档)。对于html来说,就是当一个元素产生了一个事件,它会把这个事件传递给它的父元素,父元素接收到了之后,还要继续传递给它的上一级元素,就这样一直传播到document对象(亲测现在的浏览器到window对象,只有IE8及下不这样);

    再多说一句,现在的浏览器默认是采用的是事件冒泡;在DOM0级方法绑定事件只能是事件冒泡,不能设置;在DOM2级你可以设置是用事件冒泡还是事件捕获(下面说);

    说了半天冒泡有可能没太听懂,上代码就知道了:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>事件冒泡</title>
      <style type="text/css">
      #child{
        background: red;
        50px;
        height:50px;
      }
      #father{
        100px;
        height:100px;
        background:green;
      }
      #grandparent{
        150px;
        height:150px;
        background:black;
        margin:100px auto 0;
      }
      </style>
    </head>
    <body>
      <div id='grandparent'>
        <div id='father'>
          <div id='child'></div>
        </div>
      </div>
    </body>
    <script type="text/javascript">
      var grandparent = document.getElementById("grandparent");
      var parent = document.getElementById("father");
      var child = document.getElementById('child');
      var html = document.getElementsByTagName("html")[0];
      var body = document.body;
      child.onclick = function () {
        console.log("我是儿子");
      }
      parent.onclick = function () {
        console.log("我是父亲");
      }
      grandparent.onclick = function () {
        console.log("我是爷爷");
      }
    
      window.onclick = function () {
        console.log("我是window");
      }
      document.onclick = function () {
        console.log("我是document");
      }
      html.onclick = function () {
        console.log("我是html");
      }
      body.onclick = function () {
        console.log("我是body");
      }
    </script>
    </html>
    事件冒泡代码

    当我点击红色部分

    会打印这样:

    我测试了(PS:我用的都是最新版的)chrome,firefox,opera,IE11,IE10,IE9都是这个结果,也就是说现在都冒泡到window对象,不仅仅是到document对象,但是IE8及之前的就冒泡到document就结束了;

    这就是事件冒泡,它会把你这个click事件,一级一级的向上传递,如果相应的元素也绑定click事件处理程序(这里强调是click事件,如果你是给绑定了其它事件,那没用),那么它的这个事件处理程序也会执行,也就产生了上面的结果了;

    形象的就是跟水里的鱼吐泡泡似的,慢慢的向上传递;

    • 事件捕获

      事件捕获是网景(Netscape)提出来的,事件捕获是不太具体的元素应该更早接受到事件,而最具体的节点应该最后接收到事件。他们的用意是在事件到达目标之前就捕获它;也就是跟冒泡的过程正好相反,以html的click事件为例,document对象(DOM级规范要求从document开始传播,但是现在的浏览器是从window对象开始的)最先接收到click事件的然后事件沿着DOM树依次向下传播,一直传播到事件的实际目标;我测试了一下(我用的都是最新的浏览器),chrome,opera,firefox,IE11到IE9都支持事件捕获。

    代码等着我在下面讲DOM事件流再一块说明;

    • DOM事件流

      DOM2级中规定了事件流要包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。这是W3C采用了他们两家的事件监听机制。(说点题外话,w3c中的很多标准就是这样,浏览器厂商有很多自己的私有解决问题方式,好用的就被W3c采纳了)DOM2级还规定,实际发生事件的元素在捕获阶段不能接收到事件。我们就以上面的事件冒泡时的代码说明这个过程:按照标准是这样的,当一个元素产生了事件,事件是从document到html再到body再到DIV爷爷再到DIV爸爸,这时候捕获阶段就应该停止了,再进入下一个阶段“处于目标阶段”,然后是从DIV爸爸到DIV爷爷再到body再到html再到document,这就是事件冒泡阶段;实际上我们把处于目标阶段即第二阶段看作是冒泡阶段的一部分,即冒泡的开始;实际上是怎么样的呢?先上代码,还是前面的代码只是改了一下js代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>事件冒泡</title>
      <style type="text/css">
      #child{
        background: red;
        50px;
        height:50px;
      }
      #father{
        100px;
        height:100px;
        background:green;
      }
      #grandparent{
        150px;
        height:150px;
        background:black;
        margin:100px auto 0;
      }
      </style>
    </head>
    <body>
      <div id='grandparent'>
        <div id='father'>
          <div id='child'></div>
        </div>
      </div>
    </body>
    <script type="text/javascript">
      var grandparent = document.getElementById("grandparent");
      var parent = document.getElementById("father");
      var child = document.getElementById('child');
      var html = document.getElementsByTagName("html")[0];
      var body = document.body;
      grandparent.addEventListener("click",function () {
        console.log("I am capturing grandparent");
      },true);
      grandparent.addEventListener("click",function () {
        console.log("I am grandparent");
      },false);
       parent.addEventListener("click",function() {
        console.log("I am parent");
      },false);
      parent.addEventListener("click",function() {
        console.log("I am capturing parent");
      },true);
       child.addEventListener("click",function() {
        console.log("I am capturing child");
      },true);
      child.addEventListener("click",function() {
        console.log("I am child");
      },false);
      
      body.addEventListener("click",function() {
        console.log("I am body");
      },false);
      body.addEventListener("click",function() {
        console.log("I am capturing body");
      },true);
      html.addEventListener("click",function() {
        console.log("I am capturing html");
      },true);
      html.addEventListener("click",function() {
        console.log("I am html");
      },false);
      document.addEventListener("click",function() {
        console.log("I am capturing document");
      },true);
      document.addEventListener("click",function() {
        console.log("I am document");
      },false);
      window.addEventListener("click",function() {
        console.log("I am window");
      },false);
      window.addEventListener("click",function() {
        console.log("I am capturing window");
      },true);
    </script>
    </html>
    DOM事件流代码

    代码有点多见谅了!也是为了最能说明问题!

    打印是这样的:

    这是我点击最里面DIV儿子元素所发生的情形,可以看出捕获阶段也能触发目标元素上的事件,而不仅仅是在冒泡阶段;并且还是从window开始,到最后再以window对象结束,浏览器厂商就是任性,不把W3c看在眼里。你的标准我想实现就实现不想就不实现;

    当我把DIV爷爷的事件绑定方式换成DOM0级的方式,其他的保持不变,即

    grandparent.onclick = function() {
        console.log("我是在哪个阶段发生呢?")
      }

    是这样打印的

    再次说明了我上面在IE事件流中强调的,用DOM0级绑定事件时,事件只发生冒泡的阶段;

    有时我们想要事件流,有时不想要,想要还好说,不想要怎么办呢?怎么阻止冒泡,和捕获。这个等到我们讲事件对象(event)时再说;

  • 相关阅读:
    使用babel插件集
    使用babel
    webpack基本配置
    vue-router参数传递
    路由(二) router-link的使用
    路由使用(一)
    获取DOM
    父组件传递值给子组件(一)
    定义全局组件
    Windows下更改MySQL数据库的存储位置
  • 原文地址:https://www.cnblogs.com/todayhappy/p/4435408.html
Copyright © 2020-2023  润新知