如何从 jQuery 事件中显式执行默认操作

19

针对这个问题的跟进,我正在尝试实现一个不显眼的确认对话框。

$(document).ready(function () {
    $("[data-confirmPrompt]").click(function (event) {
        var confirmPrompt = event.currentTarget.attributes['data-confirmPrompt'].value;
        event.preventDefault();
        $.prompt(confirmPrompt, {
            buttons: { Yes: true, No: false },
            callback: function (v, m, f) {
                if (v) {
                    // User clicked Yes.  Unbind handler to avoid
                    // recursion, then click the target element again
                    $(event.currentTarget).unbind('click');
                    event.currentTarget.click();
                }
            }
        });
    });
});
当用户点击"Yes"后,我希望执行与该事件相关的默认操作。我已经通过解除jQuery处理程序并再次单击元素来实现。当提交表单或导航到不同页面时,这种方法可以正常工作,但在启用AJAX的页面中无法工作,因为我想保留jQuery事件处理程序。是否有一种通用的替代方法来执行默认操作?逻辑上类似于event.executeDefault()

几个想法。1. 让你的插件“包装”事件处理程序:$('[data-confirmPrompt]').prompt('click', function() { ... }),然后你可以轻松地解除绑定和重新绑定只触发对话框的一个特定事件处理程序。 - Alexey Lebedev
2
在 click 处理程序的顶部设置特殊值,以防止提示第二次触发。如果 ($(this).data('your-flag')) { $(this).data('your-flag', 0); return true; }。在回调中设置 data('your-flag', true),您根本不需要解除绑定点击事件。 - Alexey Lebedev
@Alexey - 谢谢,我一直在考虑你的解决方案2 - 使用标志来防止VB事件处理程序中的重入,就像我们在旧日子里做的那样。如果没有人提出更优雅的解决方案,我可能会采用它。 - Joe
显然,这个问题已经很久了,但为了后世留存,我有一个建议。使用.on('click',.off('click')代替.click.unbind('click')。然后给事件添加一个命名空间,像这样:.on('click.confirm',。然后,在移除处理程序时,使用相同的命名空间--.off('click.confirm')。这样只会解绑你刚刚注册的处理程序,而不是所有的jQuery处理程序--我怀疑你的Ajax调用仍然会起作用。这应该适用于jQuery 1.7版本。 - Codebling
我认为解决这个问题的方法是阻止事件冒泡 (event.stopPropagation()),然后 return true - jpaugh
4个回答

7

根据Alexey Lebedev在他的第二条评论中提出的建议,我的当前实现现在看起来像下面的示例,除了我还添加了自己的本地化按钮标签实现。

注意:

  • 我现在使用jqueryUI对话框小部件
  • 请注意使用.delegate,以便处理程序是“ajax-aware”的,即适用于在页面加载后添加到DOM中的元素,例如作为AJAX调用的结果
  • 使用标志防止用户在确认对话框上单击Yes时发生递归。
  • 使用jquery 1.6.4和jquery-ui-1.8.16

如果有人能提出改进意见,请加入讨论。

<!-- Examples of usage -->
<input type='submit' data-confirm="OK to delete customer 123?" ... />
<a href="..." data-confirm="OK to navigate?" ... />

<!-- Implementation -->
<script type="text/javascript">
    var confirmClickHandler = function (event) {
        if ($(event.currentTarget).data('isConfirming')) return;
        var message = event.currentTarget.attributes['data-confirm'].value;
        event.preventDefault();
        $('<div></div>')
                .html(message)
                .dialog({
                    title: "Confirm",
                    buttons: {
                        "Yes": function () {
                            $(this).dialog("close");
                            $(event.currentTarget).data('isConfirming', true);
                            event.currentTarget.click();
                            $(event.currentTarget).data('isConfirming', null);
                        },
                        "No": function () {
                            $(this).dialog("close");
                        }
                    },
                    modal: true,
                    resizable: false,
                    closeOnEscape: true
                });
    };

    $(document).ready(function () {
        $("body").delegate("[data-confirm]", "click", confirmClickHandler);
    });
</script>

4
我正在做类似的事情,这对我很有效:

我正在做类似的事情,这个方法对我来说很有效:

$('#link').click(function(e){
    if(!confirm('Are you sure you want to asdf?')){
        e.preventDefault();
    }
});

1
是的,这个方法可以解决问题,但是使用JavaScript confirm的问题在于只要它显示出来,用户就无法与选项卡浏览器上的其他标签进行交互。我使用的jQuery prompt对于当前页面是模态的,但用户仍然可以切换到其他标签页。 - Joe
@Joe 这是一个你不必担心的问题。有些浏览器实际上并不会这样做(我认为 iOS 不会)。 - Jared
如果您想添加一个格式化的段落以确认,用户必须在回答“是”或“否”之前阅读该段落,该怎么办? - usefulBee

0

我真的不知道这是否回答了你的问题,但它可能会有所帮助。

考虑以下HTML:

<button onclick="alert('Hello world!');" class="btn">Test 1</button>
<button onclick="alert(this.className);" class="btn">Test 2</button>

我已经在我的$(document).ready中添加了以下内容:
$('button').each(function() {
    var btn = $(this);
    var onClick = btn.attr('onclick');

    //replace this with _this
    onClick = onClick.replace(/this/g, "_this");

    btn.attr('onclick', '');

    btn.click(function() {
        if (confirm('Do it?')) {

            //set _this first!
            var _this = btn[0];

            eval(onClick);
        }
    });
});

看起来已经完成了工作。请查看这个jsFiddle示例:http://jsfiddle.net/KeesCBakker/4jThg/

编辑
我创建了一个更像你的问题的东西:http://jsfiddle.net/KeesCBakker/hqLH5/。只是无法确定你使用的$.prompt插件,所以我从github中找到了第一个(这个仅在Chrome中有效:S)。


2
您的解决方案似乎是专门处理onclick处理程序的确认 - 我正在寻找更通用的解决方案,因此它并没有真正回答这个问题。请查看我自己的答案,以获取我迄今为止想出的最佳解决方案。 - Joe

0
我能够通过从更具体的上下文中调用event.stopPropagation()并确保我 调用 event.preventDefault(),来实现这一点。虽然你不能显式地调用默认操作,但你可以设置条件以使默认操作发生,并尽可能多或尽可能少地执行其他操作。
    // Normal event handler
    $("[data-toggle]").click(ev => {
      switchToTab(ev.currentTarget)
      ev.preventDefault()
    })

    // Allow default handler in a specific case.
    $("[data-toggle] ul a").click(ev => {
      // Don't bubble the event to the less specific handler, above
      ev.stopPropagation()
      // An incorrect return value will also cancel the default action.
      return true
    })

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