关于DOM事件模型的理解与实践。

183 阅读2分钟

DOM2级事件模型

  1. 既存在事件冒泡过程,又存在事件捕获过程。
  2. 一般先执行事件捕获,后执行事件冒泡。如果在这个时刻(冒泡或者事件捕获),有对应的事件处理函数,则执行对应的事件处理函数。这个时刻的事件处理函数,按照注册的顺序依次执行。事件捕获过程,事件会从父元素向子元素传递,事件捕获过程则相反。在chrome 浏览器上测试的结果与firefox结果略有不同:
  • chrome 浏览器上,子元素是先执行事件捕获,然后执行事件冒泡的。
  • 在firefox和360 浏览器上,子元素是先执行事件冒泡,然后执行事件捕获的。具体可以参照后面的代码例子。
  1. 在chrome 浏览器上,可以看到DOM节点继承的和定义的所有事件。
  2. addEventListener 函数,默认是事件冒泡,如果第三个参数是true,则表示事件,注册在事件捕获阶段。

DOM 0级事件模型

  1. 不存在事件捕获过程,只存在事件冒泡过程。在父子元素上同时绑定click事件,可以看到先子元素执行,后父元素执行

代码如下:

<ul id="ulDemo">
    <li id="liDemo">Acc</li>
    <li>Bcc</li>
    <li>Ccc</li>
  </ul>

  <script>
    var ul = document.getElementById('ulDemo');
    var li = document.getElementById('liDemo');
    // 执行顺序,和父元素的事件绑定模型有关,如果父元素在冒泡阶段触发,则先执行子元素的事件,
    // 如果父元素在捕获阶段触发,则先执行父元素的事件
    // ul.addEventListener('click', function(e) {
    //   console.log(4444, 'e', e);
    //   // return false;
    // }, false);
    
    ul.onclick = function(e) {
      console.log('ul', 'DOM 0 级事件', e);
    };
    // 覆盖了上面定义的onclick事件
    ul.onclick = function(e) {
      console.log('ul', 'DOM 0级事件绑定第二次', e);
    }

    li.onclick = function(e) {
      console.log('li', 'DOM 0级事件 子元素执行事件111', e);
    }
    li.onclick = function(e) {
      console.log('li', 'DOM 0级事件 子元素执行事件222', e);
    };

在浏览器中观察到如下效果:

li DOM 0级事件 子元素执行事件222 MouseEvent {isTrusted: true, screenX: 175, screenY: 132, clientX: 57, clientY: 14, …}

ul DOM 0级事件绑定第二次 MouseEvent {isTrusted: true, screenX: 175, screenY: 132, clientX: 57, clientY: 14, …}

DOM2级事件和DOM0 级事件

  1. DOM 0级事件,如果重复定义,会覆盖彼此.
  2. DOM 2级事件,如果重复定义,会依次执行.
  3. DOM 0级事件和DOM2级可以同时存在。

实例Demo

<html>
<head>
  <title>测试事件执行顺序</title>
</head>

<body>
  <ul id="ulDemo">
    <li id="liDemo">Acc</li>
    <li>Bcc</li>
    <li>Ccc</li>
  </ul>

  <script>
    var ul = document.getElementById('ulDemo');
    var li = document.getElementById('liDemo');
    // 执行顺序,和父元素的事件绑定模型有关,如果父元素在冒泡阶段触发,则先执行子元素的事件,
    // 如果父元素在捕获阶段触发,则先执行父元素的事件
    ul.addEventListener('click', function(e) {
      console.log(4444, 'e', e);
      // return false;
    }, false);
    
    ul.onclick = function(e) {
      console.log('0000', 'DOM 0 级事件', e);
    };
    // 覆盖了上面定义的onclick事件
    ul.onclick = function(e) {
      console.log('0000', 'DOM 0级事件绑定第二次', e);
    }
    
    li.addEventListener('click', function(e) {
      console.log(2222, 'e', e);
      
    }, false);
    li.addEventListener('click', function(e) {
      console.log(333, 'e', e);
      
    }, true);

    ul.addEventListener('click', function(e) {
      console.log(1111, 'e', e);
      //e.stopPropagation();
      // return false;
    }, true);
  </script>
</body>

</html>
  • 以上代码的执行结果
  1. 在chrome 浏览器上的执行结果为:

1111 'e' PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}

333 'e' PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}

2222 'e' PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}

4444 'e' PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}

  1. 在firefox 浏览器上和360上的执行结果为:

1111 "e" MouseEvent {isTrusted: true, screenX: 184, screenY: 140, clientX: 65, clientY: 21, …}

2222 "e" MouseEvent {isTrusted: true, screenX: 184, screenY: 140, clientX: 65, clientY: 21, …}

333 "e" MouseEvent {isTrusted: true, screenX: 184, screenY: 140, clientX: 65, clientY: 21, …}

4444 "e" MouseEvent {isTrusted: true, screenX: 184, screenY: 140, clientX: 65, clientY: 21, …}