为什么 onClick 事件会触发两次?

40
我有以下的HTML内容:
<span onclick="alert('Boem')">
    <button id="test1">test</button>
</span>

当我调用以下 JavaScript 代码时:
$('#test1').trigger('click');

点击事件被触发了两次,而我期望它只触发一次。因为jQuery应该在DOM树中查找并找到只有一个onclick。

我无法控制这个span,它是由第三方工具生成的。但是我可以控制按钮及其参数。

你可以在这里找到一个JSFiddle示例: http://jsfiddle.net/Voga/v4100zke/

我不知道span的onclick监听器的内容。这也是由第三方工具生成的。我希望点击触发器像现在一样执行此onclick,但只执行一次。


1
请使用以下代码:<span> <button id="test1" onclick="alert('Boem')">测试</button> </span> - cracker
https://dev59.com/4W445IYBdhLWcg3w9Oss - turtle
1
至少如果您无法控制该span,您可以执行$('#test1).parent().trigger('click') - Hemadeus
1
可能是为什么label元素的onclick事件会触发两次的重复问题。 - Martijn
13个回答

38

它会调用两次,因为按钮位于一个标签内,而标签有onclick="alert('Boem')",所以当你点击按钮时,它会显示一个警告,并且相同的点击事件会传播到标签并再次显示警告。

你需要使用以下代码停止按钮的默认行为:

$(function(){
    $('#test1').click(function(e){e.preventDefault();}).click();
});

演示


但是我确实想向父级跨度传播,因为那是单击事件所在的位置(我无法控制它)。 我只想让它触发一次事件,以便仅显示“boem”一次。 - Dommicentl
页面加载时是否需要触发点击事件? - Bhushan Kawadkar
不,这不是一个要求。 - Dommicentl
你有没有检查我的更新答案演示链接,这是你要找的吗?你的具体需求是什么? - Bhushan Kawadkar
也可以使用以下代码:$(function(){ $('#test1').click(function(e){ e.stopImmediatePropagation(); }); }); - Tolgahan Özgür
显示剩余7条评论

35

我也遇到了一个类似的问题,需要下载的pdf被下载了两次。我使用了jQuery的stopImmediatePropagation方法。

$( "#test1" ).on("click", function(e) {
     e.stopImmediatePropagation();
});

$('#test1').trigger('click');

stopImmediatePropagation将阻止任何父处理程序和其他处理程序执行。有关详细信息,请参见此处


1
在我的情况下,这个方法奏效了。谢谢! - OnTheFly
1
完美的,谢谢! - AShah
1
这个答案完全符合被接受的标准! - Shashikumar Misal

12
要停止事件传播,使用:stopPropagation
$( "#test1" ).on( "click", function(ev) {
    ev.stopPropagation();
});

$('#test1').trigger('click');

请注意DOM中分配事件的顺序。

演示


5
冒泡。子元素(span)上的单击事件也会在父元素上发生。

5
为什么它会触发两次?我知道按钮上的触发器也会触发其父元素,因此在这种情况下是span,但它是唯一具有onclick事件的元素。所以我期望这个onclick只会触发一次? - Dommicentl

1

我也遇到了模态窗口的问题

通过以下技巧解决 -

$('#saveButton').off('click').on('click', { modal: modal }, save)

这里的off('click')可以防止保存方法被触发多次。

0

请注意您已经使用了jQuery的click方法。它将触发DOM的鼠标点击事件和jQuery的点击事件。然后,jQuery的点击事件和DOM的鼠标点击事件都会传播到元素,并且它的onclick监听器会被触发两次,因此会弹出两次警报。

查看这个演示以弄清楚。

至于如何处理它,只需像之前的答案中所示使用stopPropagation

$('#test1').click(function() {

  // comment this line and run, 'parent' will be alerted TWICE!!! since both mouseEvent and jQuery.Event trigger the onclick listener
  $('#children').click(function(e) {e.stopPropagation()})

});

0

我尝试了上面提供的所有建议,但不幸的是,以上任何一种方法都对我无效。

"myBtn"在我的情况下是单独的div,因此使用标志和setTimeout,我已经实现了我想要的结果。请给予建议。

我尝试过:

  1. .off()
  2. .unbind()
  3. e.stopImmediatePropagation()
  4. e.preventDefault();

以下是对我有效的工作代码,我知道这不是一个好的做法,但现在我没有任何解决方案。请给予建议。

var isClicked = false;
$("#myBtn").on("click",function(e){
    
    
        if(!isClicked){
            isClicked = true;
            console.log("button clicked");
            

            setTimeout(function(){
                isClicked = false;
            },3000);
        }

})
 

0
我曾经遇到过同样的问题。我的问题在于我使用了.trigger('.element'),而有两个元素都有这个element类。
所以,我更具体地使用了.trigger('.parent .element')来确保只有一个单击事件发生在单个元素上,而不是在两个元素上触发一个单击事件。

0
为什么onClick事件会触发两次?
这是因为冒泡的原因。正如javascript.info所说:“事件像水中的气泡一样从内部元素向上冒泡到父元素”
如何解决这个问题?
如果你的第三方工具在生成<span></span>元素时包含了onclick属性,那么这可能意味着你的工具希望你直接将作为按钮处理,而不需要像你使用<button></button>元素那样创建一个额外的按钮。
为了解决这个错误,最好的方法是通过编程方式点击包含处理程序的相同元素,以避免事件传播。

$('#test1').trigger('click');
/* Now, you can take #test1 and make it look and function as a button */

#test1 {
  padding: 10px 20px;
  color: white;
  background-color: #0078d7;
  font-size: 2rem;
  font-family: Helvetica;
}

#test1:hover {
  cursor: pointer;
  background-color: blue;
  transition: all 0.25s;
}
<!-- Script to include jQuery v3.3.1 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<span id="test1" onclick="alert('Boem')">test</span>


尽管这个回答的形式很奇怪,但它很可能不是抄袭自ChatGPT或其他来源。 - Peter Mortensen

0

这个问题将有助于回答其中的原因。

更好的方法是只需为元素分配一个点击处理程序,以便将JavaScript代码与HTML分开:

http://jsfiddle.net/v4100zke/3/

$('#test1').click(function() {
    alert('Boem')
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接