jQuery - 阻止默认事件,然后继续默认事件

137

我有一个表单,提交时需要进行一些额外的处理才能提交表单。我可以阻止默认的表单提交行为,然后进行额外的处理(基本上是调用Google Maps API并向表单添加一些隐藏字段),然后我需要提交表单。

有没有一种方法可以“阻止默认”,然后在某个时间点“继续默认”?


@FelixKling 你是指这个网址吗?https://dev59.com/2msz5IYBdhLWcg3w3btb? - M. Mimpen
10个回答

85

使用jQuery.one()

为元素附加一个事件处理程序。每个元素每个事件类型最多执行一次该处理程序。

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

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

使用one还可以防止无限循环,因为这个自定义的submit事件在第一次提交后就被解除了。


4
点击后它会再次提交 :( - curiosity
4
可能你会面临无限循环的问题。 - Mehrdad HosseinNejad Yami
1
无限循环,函数应该是 .on 而不是 .one。 - sgvolpe
1
为了防止无限循环,首先解除表单事件并提交它。 $(this).unbind(); $(this).submit(); - Robby Alvian Jaya Mulia
1
这应该被投票选为正确答案。 - Daniyal Ahmed
此解决方案已被编辑,不再导致无限循环。编辑使用 one 方法替换了 on 方法。 - Lukas

57

当你将 .submit() 事件绑定到表单并在返回(true)之前完成所需操作时,实际提交之前会发生这些操作。

例如:

$('form').submit(function(){
    alert('I do something before the actual submission');
    return true;
});

简单的例子

jquery.com上的另一个例子:http://api.jquery.com/submit/#entry-examples


2
你是在说除非执行了“return true;”语句前的所有代码,否则表单不会提交吗? - developarvin
2
是的,这正是submit()函数所做的。 - Ron van der Heijden
14
这不是一个好的例子,因为它是同步的。如果我需要做的事情是异步调用呢?所以情况是“点击提交->执行异步操作并不提交表单->在异步回调中填写表单中的一些字段->从回调中提交表单”。 - The Godfather
1
运行一些异步的jQuery代码怎么样?这也可以工作吗? - candlejack
这个对我非常有效。我用它来在提交之前控制事情,如果不正确就使用“return false”。我寻找这个解决方案一天了。非常感谢。 - livefreeor
在我的情况下,我使用了 parsley 和自己的验证方式,所以在表单提交按钮点击事件中无法处理提交表单的操作,直到验证通过。但是你的代码完美地解决了这个问题。非常感谢。 - Ozal Zarbaliyev

33

我只会这样做:

 $('#submiteButtonID').click(function(e){
     e.preventDefault();
     //do your stuff.
     $('#formId').submit();
 });

如果你只需要提交表单,那么首先使用 preventDefault 函数,然后再使用 submit() 函数。


不要在点击事件处理程序中涉及逻辑。将其委托给其他人负责。 - Royi Namir
37
这假设用户会点击一个按钮。但如果用户只是在表单内按“回车”键呢?那也会提交表单。所以,依赖于提交按钮被点击可能不是个好主意。 - StackOverflowNewbie
我只是举了一个点击的例子...因为问题中没有提到相关的代码... - bipen
2
无论如何,您提供的代码片段只有在用户单击按钮时才能起作用。这不是表单的工作方式。还有其他建议吗? - StackOverflowNewbie
绑定点击事件,阻止默认行为并触发提交按钮的点击。 - candlejack
在这种情况下,不需要使用 e.preventDefault(),因为您只是阻止按钮上的其他处理程序的执行,而不是表单的执行。 - gyo

23
      $('#myform').on('submit',function(event){
        // block form submit event
        event.preventDefault();

        // Do some stuff here
        ...

        // Continue the form submit
        event.currentTarget.submit();
  });

1
类型错误:event.currentTarget.submit 不是一个函数。 - Black
在我的情况下,我不得不使用 event.target.submit() - Niels Lucas
两者都无法正常工作(targetcurrentTarget)。 - ThePhi
1
应该使用https://api.jquery.com/event.currentTarget/。除非您的目标不是表单元素,因为只有表单可以“提交”。 - Udy Warnasuriya

20

使用这种方式会在JS中造成无限循环。 为了更好的实现,您可以使用以下方法:

var on_submit_function = function(evt){
    evt.preventDefault(); //The form wouln't be submitted Yet.
    (...yourcode...)

    $(this).off('submit', on_submit_function); //It will remove this handle and will submit the form again if it's all ok.
    $(this).submit();
}

$('form').on('submit', on_submit_function); //Registering on submit.

希望这能有所帮助!谢谢!


以下是有关编程的相关内容的翻译,仅返回翻译后的文本:实际上最好的方法是使用异步函数进行变化-https://gist.github.com/BjornMelgaard/8ba0ee9d07c20dd8c8b3550c9df3e9ef - srghma
@bjornmelgaard 我得记住async是非标准的 - Valerio Bozz

11

在我看来,这是最通用和健壮的解决方案(如果您的操作是由用户触发的,例如“用户单击按钮”):

  • 第一次调用处理程序时,请检查是谁触发了它:
    • 如果是用户触发的-执行您的操作,然后通过编程方式再次触发它(如果需要)
    • 否则-什么也不做(=“继续默认操作”)

例如,请注意这个优雅的解决方案,它可以通过修饰按钮属性来为任何按钮添加“您确定吗?”弹出窗口。如果用户没有选择退出,我们将有条件地继续默认行为。

1. 让我们为每个需要警告文本的“是否确定”的弹出窗口按钮添加:

<button class="btn btn-success-outline float-right" type="submit"  ays_text="You will lose any unsaved changes... Do you want to continue?"                >Do something dangerous</button>

2. 给所有这样的按钮附加处理程序:

$('button[ays_text]').click(function (e, from) {
    if (from == null) {  // user clicked it!
        var btn = $(this);
        e.preventDefault();
        if (confirm() == true) {
            btn.trigger('click', ['your-app-name-here-or-anything-that-is-not-null']);
        }
    }
    // otherwise - do nothing, ie continue default
});

就是这样。


1
太棒了!我不知道你可以向.trigger()传递额外的参数。 - James Hibbard

5

使用 jQuery 和对@Joepreludian的答案稍作修改:

需要记住的重要点:

  • .one(...) 而不是 .on(...) 或 .submit(...)
  • 命名函数 而不是 匿名函数,因为我们将在 回调函数 中引用它。

$('form#my-form').one('submit', function myFormSubmitCallback(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    var $this = $(this);
    if (allIsWell) {
        $this.submit(); // submit the form and it will not re-enter the callback because we have worked with .one(...)
    } else {
        $this.one('submit', myFormSubmitCallback); // lets get into the callback 'one' more time...
    }
});

您可以在下面的代码片段中更改allIsWell变量的值为truefalse,以测试功能:

$('form#my-form').one('submit', function myFormSubmitCallback(evt){
  evt.stopPropagation();
  evt.preventDefault();
  var $this = $(this);
  var allIsWell = $('#allIsWell').get(0).checked;
  if(allIsWell) {
    $this.submit();
  } else {
    $this.one('submit', myFormSubmitCallback);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="/" id="my-form">
  <input name="./fname" value="John" />
  <input name="./lname" value="Smith" />
  <input type="submit" value="Lets Do This!" />
  <br>
  <label>
    <input type="checkbox" value="true" id="allIsWell" />
    All Is Well
  </label>
</form>

祝你好运...


你确定这里需要使用 stopPropagation 吗?另外,你可以创建一个无名称函数(删除 myFormSubmitCallback)。 - Melroy van den Berg
1
@MelroyvandenBerg,“stopPropagation”并不是必需的,但我们这样做是为了避免事件传播到其他元素。如果您希望事件传播,则可以将其删除 - 此解决方案的核心功能不会受到影响。而我们使用“命名”函数的原因是为了在函数内部进行递归引用。 - Aakash

3

"无需提交循环的验证注入":

我只想在HTML5验证之前检查reCaptcha和其他一些内容,所以我做了如下操作(验证函数返回true或false):

$(document).ready(function(){
   var application_form = $('form#application-form');

   application_form.on('submit',function(e){

        if(application_form_extra_validation()===true){
           return true;
        }

        e.preventDefault();

   });
});

3

通过纯Javascript的方式,在防止默认行为后,可以提交表单。

这是因为HTMLFormElement.submit()从不调用onSubmit()。因此,在此处,我们依靠该规范奇怪性质来提交表单,就好像它没有自定义的onsubmit处理程序一样。

var submitHandler = (event) => {
  event.preventDefault()
  console.log('You should only see this once')
  document.getElementById('formId').submit()
}

查看这个示例以了解同步请求。


等待异步请求完成同样很容易:

var submitHandler = (event) => {
  event.preventDefault()
  console.log('before')
  setTimeout(function() {
    console.log('done')
    document.getElementById('formId').submit()
  }, 1400);
  console.log('after')
}

您可以查看我的示例fiddle,了解有关异步请求的内容。


如果您喜欢使用promises:

var submitHandler = (event) => {
  event.preventDefault()
  console.log('Before')
    new Promise((res, rej) => {
      setTimeout(function() {
        console.log('done')
        res()
      }, 1400);
    }).then(() => {
      document.getElementById('bob').submit()
    })
  console.log('After')
}

这里有一个关于IT技术的请求


有没有一种通用的方式,只使用纯JavaScript而不是jQuery或任何库、模块等,来在阻止默认行为并执行您的代码后执行特定触发事件的“默认操作”?嗯,延迟默认操作? - jdmayfield
@jdmayfield 或许可以将默认操作代码放入一个函数中。这样,您既可以将其用作默认操作,也可以在防止默认操作后将其用作延迟操作。 - alairock

1
你可以使用 e.preventDefault() 来停止当前操作。
然后你可以执行 $("#form").submit();
 $('#form').submit(function (e)
{
    return !!e.submit;
});
if(blabla...)
{...
}
else
{
    $('#form').submit(
    {
        submit: true
    });
}

这对我来说非常困惑... 这不会一直循环下去吗? - dapidmini

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