为什么 Javascript 事件处理程序被调用两次?

时间:2021-03-29 08:28:25

标签: javascript dom-events

当我向类的元素添加事件处理程序时,如下所示:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    var divs = document.getElementsByClassName("class1");
    var onclick = function() {
      alert("clicked");
    }
    for (var i = 0; i < divs.length; i++) {
      divs[i].addEventListener("click", onclick);
    }
  </script>
</body>

</html>

如果我点击 div 元素,警报窗口会弹出两次。但是如果我使用下面的代码,警告窗口只会弹出一次。

<html>

<head>
  <title>test</title>
</head>

<body>
  <div class="class1" id="div1">div1</div>
  <script>
    var divs = document.getElementsByClassName("class1");
    var onclick = function() {
      alert("clicked");
    }

    divs.addEventListener("click", onclick);
  </script>
</body>

</html>

以下代码也两次弹出警告窗口:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    var div = document.getElementById("div1");
    var onclick = function() {
      alert("clicked");
    }
    div.addEventListener("click", onclick);
  </script>
</body>

</html>

我想知道为什么事件处理程序被调用两次,无论我使用 addEventListener("click",onclick, true); 还是 addEventListener("click",onclick,false);

我使用火狐浏览器。

2 个答案:

答案 0 :(得分:3)

发生这种情况是因为您的 onclick 变量是一个全局变量,这意味着您在将函数分配给 onclick 时实际上是在执行此操作:

window.onclick = function () {
    alert('click');
};

因此,您将事件侦听器添加到 div window,当您单击 div 时,它会在div,还有一次在 window 上。

为避免这种情况,请使用 iife 将您的变量从全局范围中屏蔽:

<html>

<head>
  <title>test</title>
</head>

<body>

  <div class="class1" id="div1">div1</div>

  <script>
    (function () {
        var divs = document.getElementsByClassName("class1");
        var onclick = function() {
          alert("clicked");
        }
        for (var i = 0; i < divs.length; i++) {
          divs[i].addEventListener("click", onclick);
        }
    })();
  </script>
</body>

</html>

答案 1 :(得分:1)

为什么要循环。除了名称(您覆盖本机 onclick)问题之外,为什么不只添加一次?您只有一个具有唯一 ID 的 div。

使用匿名函数可以更安全地避免意外使用本机函数名

const div = document.getElementById("div1");

div.addEventListener("click", () => {
  alert("clicked");
});
<div class="class1" id="div1">div1</div>

如果您有多个元素使用同一个事件处理程序,请委托

document.getElementById("container").addEventListener("click", (e) => {
  const div = e.target.closest("div");
  if (div && div.classList.contains("class1")) {
    alert(div.id + " clicked");
  }
});
<div id="container">
  <div class="class1" id="div1">div1</div>
  <div class="class1" id="div2">div2</div>
</div>