YBFACC / blog

仅记录个人学习使用
3 stars 0 forks source link

事件机制 #47

Open YBFACC opened 3 years ago

YBFACC commented 3 years ago

事件机制

事件流阶段

  1. 事件捕获:从上级节点,向目标元素传播(html>body>div>ui>li)

  2. 目标阶段

  3. 事件冒泡:从目标元素,向上级节点传播(li>ui>div>body>html)(默认)

不是所有的事件都能冒泡,如:blur、focus、load、unload都不能

优点

  1. 有大量子组件需要绑定同一个事件时,可以绑定在父组件上。方便管理,优化性能。
  2. 对动态生成的子组件,可以统一在父组件上进行管理。

事件绑定

事件绑定的2种形式:

DOM 0级

动态绑定事件,把一个函数赋值给事件处理程序。

只能冒泡形式触发。

box1.onclick = function () {
      //......
}

注意:DOM 0级会覆盖

前函数会被后函数覆盖,前函数消失。

  <script>
    box1.onclick = function () {
      console.log('box1');
    }
    box1.onclick = function () {
      console.log('box1 two');
    }
  </script>

//box1 two

DOM 2级

通过事件监听的方式绑定事件。执行顺序与添加顺序相关。

    box1.addEventListener('click', function () {
      //......
    }, true);

removeEventListener可以移除监听。移除后,按原顺序执行。

IE中 使用attachEvent()和detachEvent(),IE8和更老的只支持冒泡。

事件触发顺序

  <div id="box1">
    <div id="box2">
      <div id="box3"></div>
    </div>
  </div>

  <script>
    box1.onclick = function () {
      console.log('box1 51561');
    }
    box2.onclick = function () {
      console.log('box2');
    }
    box3.onclick = function () {
      console.log('box3');
    }
    box1.onclick = function () {
      console.log('box1');
    }
    box1.addEventListener('click', function () {
      console.log('box1 捕获阶段');
    }, true);
    box2.addEventListener('click', function () {
      console.log('box2 捕获阶段');
    }, true);
    box1.addEventListener('click', function () {
      console.log('box1 冒泡阶段');
    }, false);
    box2.addEventListener('click', function () {
      console.log('box2 冒泡阶段');
    }, false);
    box3.addEventListener('click', function () {
      console.log('box3 冒泡阶段');
    }, false);
    box3.addEventListener('click', function () {
      console.log('box3 捕获阶段');
    }, true);

  </script>

Firefox(90.0.2 (64 位))的结果:

image-20210806175441115

Chrome(92.0.4515.107)的结果:

image-20210806175612535

可以看到Chrome的事件机制与Firefox不同。

chrome严格遵守先捕获再冒泡,Firefox是按当前元素的上绑定元素的先后顺序来决定触发顺序。

DOM 0级覆盖之后的执行顺序

  <div id="box1">
    <div id="box2">
      <div id="box3"></div>
    </div>
  </div>

  <script>
    box3.onclick = function () {
      console.log('box3');
    }
    box3.onclick = function () {
      console.log('box3 覆盖1');
    }
    box3.addEventListener('click', function () {
      console.log('box3 冒泡阶段');
    }, false);
    box3.onclick = function () {
      console.log('box3 覆盖2');
    }
    box3.addEventListener('click', function () {
      console.log('box3 捕获阶段');
    }, true);
    box3.onclick = function () {
      console.log('box3 覆盖3');
    }
  </script>

Firefox(90.0.2 (64 位))的结果:

image-20210806180952

Chrome(92.0.4515.107)的结果:

image-20210806181120654

2个浏览器执行结果相同:都是取代onclick出现的第一个位置。

事件绑定的this

  <div id="box1">
    <div id="box2">
      <div id="box3"></div>
    </div>
  </div>

  <script>
    box1.onclick = function () {
      console.log('onclick', this);
    }
    box1.addEventListener('click', function () {
      console.log('addEventListener', this);
    }, false)
  </script>

image-20210806181836690

IE6、7、8 使用attachEvent监听时,this指向window。

stopPropagation()和preventDefault()

event.stopPropagation()

阻止捕获和冒泡阶段中当前事件的进一步传播。但是,它不能防止任何默认行为的发生。

  <div id="box1">
    <div id="box2">
      <div id="box3"></div>
    </div>
  </div>

  <script>

    box1.addEventListener('click', function () {
      console.log('box1 捕获阶段');
    }, true);
    box1.addEventListener('click', function () {
      console.log('box1 冒泡阶段');
    }, false);
    box2.addEventListener('click', function (e) {
      console.log('box2 捕获阶段');
    }, true);
    box2.addEventListener('click', function () {
      console.log('box2 冒泡阶段');
    }, false);
    box3.addEventListener('click', function (e) {
      e.stopPropagation()
      console.log('box3 冒泡阶段');
    }, false);
    box3.addEventListener('click', function (e) {
      console.log('box3 捕获阶段');
    }, true);

  </script>

当节点上设置stopPropagation时,当前节点的后续监听继续执行。

在IE下:设置cancelBubble = true

event.preventDefault()

取消默认行为

在IE下:设置window.event.returnValue = false

参考

JS事件流和事件委托

理解Javascript中的事件绑定与事件委托

详解JS事件冒泡、事件捕获原型 stopPropagation()和preventDefault()作用

[event.stopPropagation](