使用event.preventDefault()后如何触发事件


155

我想举行一个活动,直到我准备解雇它为止

$('.button').live('click', function(e){

   e.preventDefault(); 

   // do lots of stuff

   e.run() //this proceeds with the normal event    

}

是否有与上述run()功能等效的功能?


默认行为仅在处理程序返回后发生。仅在以后的处理程序中允许这种行为是没有意义的。
弗雷德里克·哈米迪

7
@FrédéricHamidi不幸的是,异步内容($ .ajax,回调等)将允许发生默认行为。
vzwick 2011年

Answers:


164

不。一旦事件被取消,便被取消。

不过,您可以稍后使用标志确定您的自定义代码是否已经运行,从而重新触发该事件-诸如此类(请忽略公然的名称空间污染):

var lots_of_stuff_already_done = false;

$('.button').on('click', function(e) {
    if (lots_of_stuff_already_done) {
        lots_of_stuff_already_done = false; // reset flag
        return; // let the event bubble away
    }

    e.preventDefault();

    // do lots of stuff

    lots_of_stuff_already_done = true; // set flag
    $(this).trigger('click');
});

更通用的变体(具有避免全局名称空间污染的附加好处)可以是:

function onWithPrecondition(callback) {
    var isDone = false;

    return function(e) {
        if (isDone === true)
        {
            isDone = false;
            return;
        }

        e.preventDefault();

        callback.apply(this, arguments);

        isDone = true;
        $(this).trigger(e.type);
    }
}

用法:

var someThingsThatNeedToBeDoneFirst = function() { /* ... */ } // do whatever you need
$('.button').on('click', onWithPrecondition(someThingsThatNeedToBeDoneFirst));

额外的超简约jQuery插件,Promise支持:

(function( $ ) {
    $.fn.onButFirst = function(eventName,         /* the name of the event to bind to, e.g. 'click' */
                               workToBeDoneFirst, /* callback that must complete before the event is re-fired */
                               workDoneCallback   /* optional callback to execute before the event is left to bubble away */) {
        var isDone = false;

        this.on(eventName, function(e) {
            if (isDone === true) {
                isDone = false;
                workDoneCallback && workDoneCallback.apply(this, arguments);
                return;
            }

            e.preventDefault();

            // capture target to re-fire event at
            var $target = $(this);

            // set up callback for when workToBeDoneFirst has completed
            var successfullyCompleted = function() {
                isDone = true;
                $target.trigger(e.type);
            };

            // execute workToBeDoneFirst callback
            var workResult = workToBeDoneFirst.apply(this, arguments);

            // check if workToBeDoneFirst returned a promise
            if (workResult && $.isFunction(workResult.then))
            {
                workResult.then(successfullyCompleted);
            }
            else
            {
                successfullyCompleted();
            }
        });

        return this;
    };
}(jQuery));

用法:

$('.button').onButFirst('click',
    function(){
        console.log('doing lots of work!');
    },
    function(){
        console.log('done lots of work!');
    });

4
.live被描述。使用下面@Cory Danielson示例中使用的.on。
nwolybug,2015年

这再次进入.click中,最后我看到“太多递归”
Himanshu Pathak

5
@HimanshuPathak-您可能忘记了设置lots_of_stuff_already_done = true;标志-否则该函数将无法继续递归。
vzwick

73

接受答案的最新版本。

简要版本:

$('#form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.lots_of_stuff_done ) {
        e.preventDefault();
        $.ajax({
            /* do lots of stuff */
        }).then(function() {
            // retrigger the submit event with lots_of_stuff_done set to true
            $(e.currentTarget).trigger('submit', { 'lots_of_stuff_done': true });
        });
    } else {
        /* allow default behavior to happen */
    }

});



此类情况的一个好用例是您可能有一些旧的表单代码有效,但是在提交表单之前,系统要求您通过添加诸如电子邮件地址验证之类的内容来增强表单。您不必编写后端表单的邮政编码,而可以编写一个API,然后更新您的前端代码以首先命中该API,然后再允许表单执行传统的POST。

为此,您可以实现类似于我在此处编写的代码:

$('#signup_form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.email_check_complete ) {

        e.preventDefault(); // Prevent form from submitting.
        $.ajax({
            url: '/api/check_email'
            type: 'get',
            contentType: 'application/json',
            data: { 
                'email_address': $('email').val() 
            }
        })
        .then(function() {
            // e.type === 'submit', if you want this to be more dynamic
            $(e.currentTarget).trigger(e.type, { 'email_check_complete': true });
        })
        .fail(function() {
            alert('Email address is not valid. Please fix and try again.');
        })

    } else {

        /**
             Do traditional <form> post.
             This code will be hit on the second pass through this handler because
             the 'email_check_complete' option was passed in with the event.
         */

        $('#notifications').html('Saving your personal settings...').fadeIn();

    }

});

1
“而不是挖掘后端表单的邮政编码” ...实际上,无论如何您都必须这样做,您不能仅依靠客户端验证。
Diego V


16

isDefaultPrevented像这样覆盖属性:

$('a').click(function(evt){
  evt.preventDefault();

  // in async handler (ajax/timer) do these actions:
  setTimeout(function(){
    // override prevented flag to prevent jquery from discarding event
    evt.isDefaultPrevented = function(){ return false; }
    // retrigger with the exactly same event data
    $(this).trigger(evt);
  }, 1000);
}

恕我直言,这是使用完全相同的数据重新触发事件的最完整方法。


e未定义。应该是evt.preventDefault()。我尝试进行编辑,但是我的编辑必须大于6个字符,而我刚刚添加了2 :(
kevnk

3
@kevnk,我通常以行注释的形式简要介绍编辑内容。这应该增加提交的字符数。
递归

不知道为什么这个答案没有得到更多支持,这真的很有用。传播也可以通过停止event.isPropagationStopped = function(){ return false; };。我还向事件添加了一个自定义属性,以便可以在处理程序中检测是否阻止了该操作的检查已完成,因此不再进行检查。大!
卡达斯

我使用了Bootstrap 4标签,它工作得很好。非常感谢。$('#v-pills-tab a')。on('click',function(e){e.preventDefault(); setTimeout(function(){e.isDefaultPrevented = function(){return false;} $( '#v-pills-home-tab')。on('shown.bs.tab',function(){$('。mainDashboard')。show(); $('#changePlans')。hide(); });},1000); $(this).tab('show');});
Surya R Praveen

8

它是可以使用currentTargetevent。示例显示了如何进行表单提交。同样,您可以从onclick属性等获取功能。

$('form').on('submit', function(event) {
  event.preventDefault();

  // code

  event.currentTarget.submit();
});

提交不是有效的函数
Devaffair

如果调用submit()相同的元素,是否不返回``$('form')。on('submit')代码并一遍又一遍地重做?
尼·沃伊德

7

只是不执行e.preventDefault();或有条件地执行。

原始事件动作发生,您当然不能更改。

如果您想稍后再“重新创建”原始的UI事件(例如,在AJAX请求的回调中),则只需以其他方式伪造它(例如在vzwick的回答中)...尽管我会质疑这种方法的可用性。



3

只要“很多东西”没有做异步操作,那绝对是没有必要的-该事件将按顺序调用每个处理程序,因此,如果父元素上有onklick-event,则在onclik-之后会触发孩子的事件已完全处理。javascript在此处不执行某种“多线程”处理,因此“停止”事件处理成为必需。结论:“暂停”事件只是在同一处理程序中恢复它没有任何意义。

如果“很多东西” 异步的,那么这也是没有意义的,因为它阻止了异步的事情去做他们应该做的事情(异步的东西),并使它们像一切都是顺着的那样行为(我们回到我的第一段) )


中间的过程是异步的,我想在ajax回调中触发结果...
Mazatec 2011年

1
如果您必须等待ajax请求使其同步(对于jquery,则存在async-fag:api.jquery.com/jQuery.ajax)...但是使同步ajax请求几乎是一个坏主意,因此最好找到其他解决方案。
oezi 2011年

3

我使用的方法是这样的:

$('a').on('click', function(event){
    if (yourCondition === true) { //Put here the condition you want
        event.preventDefault(); // Here triggering stops
        // Here you can put code relevant when event stops;
        return;
    }
    // Here your event works as expected and continue triggering
    // Here you can put code you want before triggering
});

2

如果您正在使用锚标记,则可接受的解决方案将无法正常工作。在这种情况下,您将无法在致电后再次单击该链接e.preventDefault()。那是因为jQuery生成的click事件只是本机浏览器事件之上的一层。因此,在锚标记上触发“点击”事件将不会跟随该链接。相反,您可以使用类似jquery-simulate的库,该库将允许您启动本机浏览器事件。

有关此的更多详细信息,请参见此链接。


1

另一个解决方案是在事件侦听器中使用window.setTimeout 并在事件处理完成后执行代码。就像是...

window.setTimeout(function() {
  // do your thing
}, 0);

因为我不关心等待,所以我在这段时间内使用0


1

我知道这个话题很老,但我认为我可以有所作为。如果您已经知道事件的默认行为,则可以随时在处理函数中触发该事件的默认行为。例如,当您触发“重置”按钮上的click事件时,实际上是在最接近的窗体上调用重置功能作为默认行为。在处理程序函数中,使用preventDefault函数后,您可以通过在处理程序代码中任何位置的最接近的窗体上调用reset函数来调用默认行为。


0

如果此示例可以帮助您,请在某些链接上添加“自定义确认弹出窗口”(我保留了代码“ $ .ui.Modal.confirm”,这只是执行原始操作的回调的一个示例):

//Register "custom confirm popin" on click on specific links
$(document).on(
    "click", 
    "A.confirm", 
    function(event){
        //prevent default click action
        event.preventDefault();
        //show "custom confirm popin"
        $.ui.Modal.confirm(
            //popin text
            "Do you confirm ?", 
            //action on click 'ok'
            function() {
                //Unregister handler (prevent loop)
                $(document).off("click", "A.confirm");
                //Do default click action
                $(event.target)[0].click();
            }
        );
    }
);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.