【问题标题】:How to trigger an event after using event.preventDefault()使用 event.preventDefault() 后如何触发事件
【发布时间】:2011-11-28 11:30:50
【问题描述】:

我想举办一个活动,直到我准备好触发它,例如

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

   e.preventDefault(); 

   // do lots of stuff

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

}

是否有与上述run() 函数等效的函数?

【问题讨论】:

  • 默认行为仅在您的处理程序返回后发生。阻止这种行为只是为了稍后在您的处理程序中允许它是没有意义的。
  • @FrédéricHamidi 不幸的是,异步内容($.ajax、回调等)将允许发生默认行为。

标签: jquery jquery-events


【解决方案1】:

不。活动一经取消,即被取消。

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

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));

带有Promise 支持的超简约 jQuery 插件:

(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!');
    });

【讨论】:

  • .live 已被贬低。使用 .on 在下面的@Cory Danielson 示例中使用。
  • 这又进入了.click,最后我看到“递归太多”
  • @HimanshuPathak - 你可能忘记设置 lots_of_stuff_already_done = true; 标志 - 否则函数无法继续递归。
【解决方案2】:

已接受答案的更新版本。

简要版:

$('#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,然后更新您的前端代码以在允许表单执行传统 POST 之前首先访问该 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();

    }

});

【讨论】:

  • “而不是挖掘后端表单邮政编码”...事实上你无论如何都必须这样做,你不能仅仅依赖客户端验证。
【解决方案3】:

你可以这样做

$(this).unbind('click').click();

【讨论】:

  • 这是一个非常好的解决方案 - 但似乎不适用于 IE10/11 ;(
  • 为什么要删掉“疼痛”这个词?
  • 您触发了点击,但您可以再次点击吗?
【解决方案4】:

像这样覆盖属性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,我通常以行注释的形式包含编辑的简短描述。这应该会增加提交的字符数。
  • 不知道为什么这个答案没有得到更多的支持,这真的很有用。 event.isPropagationStopped = function(){ return false; }; 也适用于传播停止。我还向事件添加了一个自定义属性,以便我可以在处理程序中检测是否已完成阻止该操作的检查,因此不会再次进行。太好了!
  • 我用于 Bootstrap 4 Tabs,效果很好。非常感谢。 $('#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'); });
  • 这个不会循环吧,click evt基本又触发了。
【解决方案5】:

最近的回答巧妙地使用了jQuery.one()

$('form').one('submit', function(e) {
    e.preventDefault();
    // do your things ...

    // and when you done:
    $(this).submit();
});

https://stackoverflow.com/a/41440902/510905

【讨论】:

    【解决方案6】:

    可以使用event 中的currentTarget。 示例显示如何继续进行表单提交。同样,您可以从onclick 属性等获取函数。

    $('form').on('submit', function(event) {
      event.preventDefault();
    
      // code
    
      event.currentTarget.submit();
    });
    

    【讨论】:

    • 提交不是一个有效的函数
    • 如果你在同一个元素上调用submit(),你会不会返回你的``$('form').on('submit') 代码并一遍又一遍地重做它?跨度>
    【解决方案7】:

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

    您当然无法更改何时原始事件动作发生。

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

    【讨论】:

      【解决方案8】:

      我使用的方法是这样的:

      $('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
      });
      

      【讨论】:

        【解决方案9】:

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

        如果“很多东西”异步的,这也没有意义,因为它会阻止异步的事情做他们应该做的事情(异步的事情),并使他们变得像一切都在序列(我们回到我的第一段)

        【讨论】:

        • 中间的过程是异步的,我想在ajax回调中触发结果...
        • 如果你必须等待一个 ajax 请求,让它同步(对于 jquery,有 async-fag: api.jquery.com/jQuery.ajax)...但是同步 ajax 请求是个坏主意几乎在所有情况下,最好找到不同的解决方案。
        【解决方案10】:

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

        更多详情请见link

        【讨论】:

          【解决方案11】:

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

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

          我用 0 表示这段时间,因为我不在乎等待。

          【讨论】:

          • 我喜欢这个解决方案。没有 jQuery 的东西。
          【解决方案12】:

          我知道这个话题很老,但我认为我可以做出贡献。如果您已经知道该行为,则可以随时在处理程序函数中触发特定元素上的事件的默认行为。例如,当您在重置按钮上触发点击事件时,您实际上是在最接近的表单上调用重置函数作为默认行为。在您的处理程序函数中,使用 preventDefault 函数后,您可以通过在处理程序代码中的任何位置调用最接近的表单上的重置函数来调用默认行为。

          【讨论】:

            【解决方案13】:

            如果这个例子有帮助,在一些链接上添加一个“自定义确认弹出框”(我保留“$.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();
                        }
                    );
                }
            );
            

            【讨论】:

              【解决方案14】:

              如果您将事件侦听器添加到表单并等待其提交,那么在检查您需要检查的内容后,您可以使用 .submit ie 调用表单提交

              const checkoutForm = document.getElementById('checkout-form');
              const cart = {};
              if (checkoutForm) {
                  checkoutForm.addEventListener('submit', e => {
                      e.preventDefault();
                      if(JSON.stringify(cart) === '{}'){
                          console.log('YOUR CART IS EMPTY')
                          alert('YOUR CART IS EMPTY');
                          return;
                      }
                      else{
                          checkoutForm.submit();
                      }
                  })
              }
              <form id="checkout-form" action="action-page" method="post">
                <input type="text" name="name" />
                <button>Submit</button>
              </form>

              这样您就可以解决表单提交问题,例如检查密码强度和检查所有需要的字段是否具有正确的数据

              【讨论】:

                【解决方案15】:

                这是我使用 preventDefault 并在内部触发“点击”的旧想法。我只是将参数“prevent”传递给函数:

                $(document).on('click', '.attachments_all', function(e, prevent = true){
                
                    if(prevent){
                
                        e.preventDefault();
                
                        var button = $(this);
                        var id = button.data('id');
                    
                        $.ajax({
                            type: 'POST',
                            url: window.location.protocol + '//' + window.location.host + path + '/attachments/attachments-in-order/' + id, 
                            dataType: 'json',
                            success: function(data){
                                if(data.success && data.attachments){ 
                                    button.trigger('click', false);
                                } else {
                                    swal({
                                        title: "Brak załączników!",
                                        text: "To zamówienie nie posiada żadnych załączników!",
                                        type: "error"
                                    });
                                    return;
                                }
                            }
                        });
                    }
                
                });
                

                希望有人会觉得有用

                【讨论】:

                  【解决方案16】:

                  您可以将它与 Timer 或不使用 Timer 一起使用。

                  const form = document.querySelector('#form');

                  form.addEventListener('submit', (x) => {

                  x.preventDefault()
                  
                  // Ajax or nay Code
                  
                  setTimeout(() => {
                      x.target.submit();
                  }, 1000)
                  

                  })

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-01-20
                    • 2023-03-12
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-01-20
                    相关资源
                    最近更新 更多