📜  onclick 事件触发两次 (1)

📅  最后修改于: 2023-12-03 15:33:17.167000             🧑  作者: Mango

onclick 事件触发两次

在网页开发中,当我们使用 onclick 事件时,有时候会遇到事件触发两次的问题,这一问题可能导致数据的错误或不完整,因此需要我们及时解决。

问题原因

事件会触发两次的原因通常是出现了冒泡和捕获的问题,也可能是代码逻辑的问题导致的。以下我们将逐个介绍这两个问题。

冒泡和捕获

冒泡和捕获是指当事件发生时,它的处理顺序。HTML 标准规定事件发生后,从最具体的元素(文本节点)开始,逐级向上传播到 全局对象 ,称为 冒泡 (bubble)的过程;然后再由全局对象逐级向下捕获(capture)至最具体的元素的过程。如下图所示:

event-flow

通常情况下,当我们添加 onclick 事件时,事件触发顺序是 click > bubble(冒泡) > bubble > capture(捕获)。如果在冒泡和捕获的过程中都会触发事件处理函数,就会导致事件被触发两次。

代码逻辑问题

事件被触发两次的原因也可能是代码逻辑问题,例如:

  • 常见的错误:两个相同的事件处理器。如下所示:

    <button onclick="clickHandler()">Click me</button>
    <script>
      function clickHandler() {
        console.log('click');
      }
      // other code ⋯
      // 函数可能会意外被多次定义
      function clickHandler() {
        console.log('click again')
      }
    </script>
    

    上述代码定义了两个 clickHandler 函数,因此点击 button 时事件处理函数就会被调用两次。

  • 嵌套事件:在一个按钮上嵌套点击事件,容易导致事件被调用两次。

解决方案
解决冒泡和捕获问题

阻止冒泡和捕获

我们可以在事件处理函数中使用 event.stopPropagation() 方法阻止事件的冒泡和捕获。例如:

function clickHandler(event) {
  event.stopPropagation();
  // 事件处理代码 ⋯
}

在上述代码中,event.stopPropagation() 方法会阻止事件的冒泡和捕获,从而避免事件处理函数被执行两次。

改变监听事件的阶段

我们也可以使用 addEventListener() 方法的 useCapture 参数来修改事件监听的阶段。例如:

element.addEventListener(eventName, eventHandler, true);

在上述代码中,true 表示改变事件监听的阶段为捕获(capture)。这样就避免了事件被触发两次的问题。

解决代码逻辑问题

避免重复定义事件处理函数

我们应该避免重复定义事件处理函数。例如,在上面的代码中,我们只需要定义一个 clickHandler 函数即可。如果函数被多次定义,就会导致事件处理函数被调用多次。

删除多余的事件监听器

如果对同一个元素重复绑定相同的事件处理函数,就会导致事件被触发多次。为此,我们应该在处理完事件后,将不需要的监听器移除。

element.removeEventListener('click', clickHandler);

在上述代码中,我们可以使用 removeEventListener 方法从元素上删除特定的事件监听器,防止出现重复绑定处理函数的情况。

结论

onclick 事件触发两次的问题通常是因为冒泡和捕获导致的,也可能是代码逻辑的问题。针对这些问题,我们可以使用 event.stopPropagation() 方法,修改时间监听的阶段,删除多余的事件监听器等方法来解决问题。因此,我们务必关注这一问题,并在开发和调试过程中及时解决。