防止JQuery触发多次点击事件

26

这是情景描述,我的内容基于一个类异步加载。所以如果我有一个带有ajaxLink类的链接,它将按照以下方式触发:

$('a.ajaxLink').click(function (e) {
        e.preventDefault();
        var container = $(this).parents('div.fullBottomContent');
        var href = $(this).attr('href');
        container.fadeOut('fast', function () {
            $.ajax({
                url: href,
                dataType: "html",
                type: "GET",
                success: function (data) {
                    container.html(data);
                    BindEventHandlers();
                    container.fadeIn();
                    $.validator.unobtrusive.parse('form');
                },
                error: function () {
                    alert('An error has occurred');
                }
            });
        });

    });

一切都很好。现在有个情况是,我想向用户显示一个警告框,确认他们是否要加载页面并丢失所有更改,因此我编写了以下代码:

$('a.addANewHotel').click(function (e) {
        if (!confirm('Adding a new hotel will loose any unsaved changes, continue?')) {
            e.stopPropagation();
        }
    });

我已经尝试过return false, e.preventDefault()e.stopPropagation();,但不管怎样,第一种方法总是被触发?如何防止多余的点击事件被触发?这是一个事件顺序的问题吗?

我不认为这和我的HTML有关:

<a style="" href="/CMS/CreateANewHotel?regionID=3&amp;destinationID=1&amp;countryName=Australia" class="button wideBorderlessButton ajaxLink addANewHotel">Add a new hotel</a>

你的HTML长什么样? - Asciiom
1
我不明白你为什么要将两个不同的事件绑定到同一个元素上。我会根据点击了哪个元素来显示/隐藏确认消息,但都在同一个点击事件内完成(例如,使用hasClass if) - Th0rndike
当然相关,只有现在我们知道有一个带有几个类的a标签,并且你将两个点击处理程序绑定到同一个a标签。 - Asciiom
@ThOrndike 我想我可以这样做,但这并不是很优雅。Ajax链接代码有效,似乎把它弄得很复杂会很可惜。 - Liam
你在帖子中写的两个 $(..).click() 调用是按照相同的顺序执行的吗? - FixMaker
2个回答

53

你试过这个方法吗:event.stopImmediatePropagation

我认为这就是你要找的方法:

http://api.jquery.com/event.stopImmediatePropagation/

$('a.addANewHotel').click(function (e) {
        if (!confirm('Adding a new hotel will loose any unsaved changes, continue?')) {
            e.stopImmediatePropagation();
            e.preventDefault();
        }
    });

1
无法工作。他在同一元素上有两个处理程序,这只会阻止传播到父元素,并不能帮助他解决这个问题。 - Asciiom
2
从文档中: "阻止其它处理程序的执行并防止事件冒泡到DOM树上方。" - bstakes
改变我的想法,这是一个更好的解决方案!需要稍微调整代码,最终看起来像:if (!confirm('添加新酒店将丢失任何未保存的更改,是否继续?')) { e.stopImmediatePropagation(); e.preventDefault(); } - Liam
1
哇... 能救我一命啊!谢谢 :) 当我需要在 Angular2 下使用jQuery点击事件时,这个甚至可以工作!!! - normalUser

3

stopPropagation会阻止事件冒泡到父元素,但不会防止同一个元素上的其他点击处理程序触发。因此,您的解决方案不起作用。

例如,您可以像这样实现:

$('a.ajaxLink').click(function (e) {
    e.preventDefault();

    if($(this).hasClass("a.addANewHotel") &&
           !confirm('Adding a new hotel will loose any unsaved changes, continue?')){
        return false;
    }

    var container = $(this).parents('div.fullBottomContent');
    var href = $(this).attr('href');
    container.fadeOut('fast', function () {
        $.ajax({
            url: href,
            dataType: "html",
            type: "GET",
            success: function (data) {
                container.html(data);
                BindEventHandlers();
                container.fadeIn();
                $.validator.unobtrusive.parse('form');
            },
            error: function () {
                alert('An error has occurred');
            }
        });
    });

});

如果您有许多不同类型的链接,应该将通用代码放在一个函数中,并使用不同的类绑定处理程序。然后,这些处理程序可以在适当的时候调用通用代码。

+1 是的,我可以。不过如果我不必在通用的 ajaxLink 点击事件中添加大量的 if else 语句会更好。 - Liam
取决于你是否有很多需要不同处理方式的不同链接,否则这会变得混乱。但对于这个例外情况,我认为这是可以接受的。附加建议已添加到答案中。 - Asciiom

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