jQuery绑定点击事件立即触发的问题

3
我有一个下拉菜单,点击图标应该向其父元素添加类“Open”,然后在任何地方点击菜单时都应该关闭它。但是,在绑定内部的函数在单击图标时就会触发。效果是它添加了类Open,然后立即将其删除。
这可能是一个简单的问题,但我似乎无法解决为什么'click'事件会立即触发!
这个问题可能类似,但仍然无法解决: jQuery bind event firing the event
$(function () {

    $(".ui-dropdown-action").bind("click", function () {
        $(this).parent()
            .addClass("Open")
            .bind("click", function () {
                $(this).removeClass("Open");
            });
    });

});

你尝试过使用on()而不是bind()吗?On和bind的工作方式不同,我曾经使用bind时遇到了类似的问题。此外,现在更倾向于使用On而不是bind。 - Zappa
建议阅读:MDN有关事件传播的示例 - bfavaretto
从jQuery 1.7开始,.on()方法是附加事件处理程序到文档的首选方法。 - Aesthete
4个回答

8

我认为您可能存在点击事件在DOM树中向上传播的问题。这就是为什么单击事件也会在其父元素上触发的原因。

如果您将事件对象作为第一个绑定的参数传递,并像下面这样调用event.stopPropagation()

$(function () {

  $(".ui-dropdown-action").bind("click", function (event) {
    event.stopPropagation();
    $(this).parent()
        .addClass("Open")
        .bind("click", function () {
            $(this).removeClass("Open");
        });
  });

});

你可以尝试以下解决方案来解决你的问题。

这并没有解决代码中的其他问题,只是暂时掩盖了它们。 - I Hate Lazy
他的问题是关于事件冒泡的。不是将多个事件监听器绑定到同一个处理程序。这是一个单独的问题,不是他问题的原因。它不会掩盖任何东西。无论父元素附加了多少次点击事件监听器,他都不希望事件冒泡到父级。 - Mark
是的,你说得对。别管他。希望他将来能自己找到自己的漏洞。 - I Hate Lazy
提出改进别人的代码的建议是很好的。然而,如果这些建议不能回答问题,那么它们不值得作为答案,而应该作为评论。 - Mark
不同的教学哲学,我猜。 - I Hate Lazy

0
你可以传递事件参数并停止事件冒泡.. 试试这个。
$(function () {

        $(".ui-dropdown-action").bind("click", function () {
            $(this).parent()
                .addClass("Open")
                .unbind().bind("click", function (e) {
                    $(this).removeClass("Open");
                    e.stopPropagation();
                });
        });

    });

这将确保在单击图标时不触发父事件.. 此外,每次单击图标时,都会重新绑定父级的事件,这将创建多个单击事件.. 需要确保您解除绑定并再次绑定它们以避免出现这种情况..

显然这是正确的方法,但因为它第一次触发,e.stopPropagation() 应该在更高的级别上(在第一个绑定内部)。不过还是谢谢! - jamie-wilson
常量绑定/解绑是一种反模式,通常表明您正在做错事情。 - I Hate Lazy
没错,但是每次你点击dropdown-action类时,都会将一个新的点击事件绑定到父类上.. 你希望如何控制这种行为呢..?? - Sushanth --
类似这样的代码。还有其他的解决方案。我对嵌套处理程序持怀疑态度,但在没有更多信息的情况下无法确定是否适当。如果您发布更符合惯用语的解决方案,我将会给您点赞(+1)。 - I Hate Lazy
即使点击嵌套元素也应该关闭菜单,这个可能也能解决问题。 - I Hate Lazy

0

它立即触发是因为点击事件冒泡到父级,然后触发了该选择器。要解决这个问题,您可以在第二次绑定周围使用setTimeout()。

$(function () {
  $(".ui-dropdown-action").bind("click", function () {
    var parent = $(this).parent();
    parent.addClass("Open");
    setTimeout(function() {
      parent.bind("click", function () {
        $(this).removeClass("Open");
      });
    }, 0);
  });
});

另一个选择是在第一次绑定时对事件执行stopPropagation(),但这将阻止任何其他处理程序在该事件上触发。


2
您可以阻止事件冒泡到DOM。使用setTimeout是不必要的。 - Mark
同意Mark的观点,尽管他可能有更高层级的处理程序需要在该事件上进行操作。我编辑了我的答案以反映这一点。 - f1sherman

0
在我的情况下,当我使用类似这样的东西时:
$("#modal .button")[0].click(() => console.log('test'))

它不起作用,似乎点击立即触发

对我来说的解决方案是:

const button = $("#modal .button")[0];
$(button).click(() => console.log('test'));

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