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



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

<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);,都会调用事件处理程序两次

我使用Firefox浏览器。

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

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

因此,您正在将事件侦听器添加到divs、window中,当您单击div时,它在divwindow上分别启动一次。

为了避免这种情况,请使用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>

为什么要循环。除了名称(覆盖原生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.matches(".class1")) {
alert(div.id + " clicked");
}
});
<div id="container">
<div class="class1" id="div1">div1</div>
<div class="class1" id="div2">div2</div>
</div>

唯一对我有效的解决方案是强制调用addEventListener一次。

类似:

if (!window.onClickListenerAdded) {
const onClickListener = (event) => {
alert("clicked");
};
window.removeEventListener('click', onClickListener);
window.addEventListener('click', onClickListener);
window.onClickListenerAdded = true;
}

最新更新