【问题标题】:How to avoid conflict between 2 jQuery "on form submit" scripts?如何避免 2 个 jQuery“表单提交”脚本之间的冲突?
【发布时间】:2016-06-03 15:58:02
【问题描述】:

我想要实现的是跟踪表单提交。 但是由于我们对提交按钮使用了许多变化,我想更改我当前的代码:

$(document).on('click','input[type="submit"], button[type="submit"]',function(){

到普遍的东西。我相信最好的方法是$("form")-annotation。

问题是,例如,如果 form 上有一个 ajax 脚本,它会被我的 additional 脚本代码阻止。 基本上我想要实现的是两全其美。

所以第一个是网站目前拥有的(虽然不是每个网站):

$("form").submit(function () {
  // ....do something, maybe ajax submit of the form.....
});

以及我想要添加的附加,而无需编辑网站中已有的任何当前脚本:

$("form").submit(function () {
    $.getJSON("....");
});

我的解决方案应该是第二个脚本(附加)不会干扰任何其他表单脚本。

一个想法

使用jQuery addClass在当前页面的表单中添加一个类。

对此有什么解决方案?

【问题讨论】:

  • 所有表单都没有id?
  • @RatHat 因为这将是“一刀切”的解决方案,它不能使用 ids。当然,如果我可以通过 jquery 向表单添加一个独特的类?
  • 您似乎已经尝试过了...不行吗?你在additional-Callback 里面做什么?只是getJSON 电话?
  • 我认为你应该使用Promises 或jQuery 的Deferred
  • @Ciprianis 我不知道这与 jQuery 的延迟承诺有什么关系。这个问题是关于你是否能找到一个足够强大的钩子来“接管”stopImmediatePropagation 并且以一种不引人注目的方式这样做 - 一种被通知事件的方式但实际上不会干扰其他处理程序。

标签: javascript jquery ajax forms


【解决方案1】:

我创建了一个小片段来演示这个问题:

$(document).ready(function() {

  // Registering form-submission as the first would be a possibility
  $('form').on('submit', function(e) {
    console.log(e.target);
    console.info('My first callback is executing');

    // Do some stuff here, but don't mess with the event-object 
    // (like preventing default or stopping the event-chain)
  });

  // Then afterwards everything else that *might* catch the event
  $('form').on('submit', function(e) {
    console.log(e.target);
    console.info('My second callback is executing');

    // Usually some Ajax-Handler-Callback, that handles sending the form,
    // will preventDefault() and stopImmediatePropagation() - that is why 
    // your general first listener must be registered before any of these callbacks

    console.warn('Second callback stops the event from bubbling/propagating');
    e.stopImmediatePropagation();
    e.preventDefault();
  });

  // This will never happen
  $('form').on('submit', function(e) {
    console.log(e.target);
    console.info('My third callback will never execute');
  });
  
  // Using a delegated event-listener with `useCapture` lets this execute first
  document.addEventListener('submit', function(e) {
    console.info('Capturing the event natively');
  }, true);

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<h1>My Website with a multi-handled form</h1>

<form class="" action="" method="post">
  <input type="text" name="test" value="">
  <button type="submit" name="button">Send</button>
</form>

提交表单时的片段输出:

本地捕获事件

<form class action method="post">…</form>

我的第一个回调正在执行

<form class action method="post">…</form>

我的第二个回调正在执行
第二个回调阻止事件冒泡/传播


刚刚发生了什么?

通过按下提交按钮,我们的表单会发出 submit 事件。浏览器从指定的event-order 中的事件传播开始。事件传播有两个阶段:event-capturing and event-bubbling

现在我们的第一个调用事件监听器是带有useCapture指令的监听器。
这是在事件传播捕获阶段

useCapture 的解释取自MDN

capture:一个布尔值,表示该类型的事件将被 在被分派给任何人之前分派给已注册的侦听器 DOM 树中它下方的 EventTarget。

完成后,浏览器将从 event-propagationbubbling-phase 开始。

这是所有$('element').on()element.addEventListener()(不带useCapture 选项)注册的侦听器按出现顺序调用的地方。

在这个阶段,我们的第二个监听器不仅阻止默认(不以标准方式提交表单),而且还通过调用 e.stopImmediatePropagation() 来停止事件传播。

之后,事件链/事件传播立即停止。

这就是为什么我们的第三个监听器永远不会执行。

附带说明:使用 jQuery 并退出事件回调时 return false,jQuery 将执行 e.preventDefault()e.stopPropagation() 自动。

见:http://api.jquery.com/on/


结论

您的方案基本上有两种可能性:

  1. 在其他任何事情之前注册您的默认常规事件侦听器(片段中的第一个事件注册)。

  2. 在捕获阶段注册一个事件侦听器,以便在冒泡阶段的其他侦听器被调用之前捕获事件并处理事情(Snippet 中的最后一个事件注册)。

    李>

使用这两种方法,您应该能够在不干扰其他事件侦听器的情况下完成您的工作。

【讨论】:

  • 您好,感谢您的回答。我现在无法测试它,但是如果我做对了,我必须在提交表单的脚本下方放置“第二个处理程序”脚本和“委托事件处理程序”?
  • 嗨@Xalloumokkelos,我刚刚为我的答案添加了更多解释。我希望现在一切都可以理解了,如果不是让我知道是什么让你感到困惑。
【解决方案2】:

使用这个:

    $(document).on("submit", "form", function (e){

完整示例:

    <form id="form1"><input type="text" /><input type="submit" /></form>
    <form id="form2"><input type="text" /><input type="submit" /></form>

Js:

    $(document).on("submit", "form", function (e) {
      var oForm = $(this);
      var formId = oForm.attr("id");
      var firstValue = oForm.find("input").first().val();
      alert("Form '" + formId + " is being submitted, value of first input is: " + firstValue);
      return false;
     })

     [JS fiddle]: http://jsfiddle.net/pZ3Jn/

【讨论】:

    【解决方案3】:

    我想要实现的是跟踪表单提交。

    为什么不直接使用$(document).on('submit', 'form', function(){});

    它会在每次提交表单时触发,无论它是如何提交的。

    $(document).ready(function() {
    
      // Some already existing event handler
      $('#bir').on('submit', function(e) {
        console.log($(this).attr('id'));
        e.preventDefault();
      });
    
      // Your universal form event handler
      $(document).on('submit', 'form', function(e) {
        console.log('Additional functionality for: ' + $(this).attr('id'));
      });
    
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <form id="bir">
      <input type="submit" />
    </form>
    
    <form id="ikki">
      <input type="submit" />
    </form>

    【讨论】:

    • 但是如果已经存在的事件处理程序也将e.stopImmediatePropagation() 呢?
    • 好吧,解决方案是按照您的建议进行操作,首先注册“通用”事件处理程序。我认为在document 上注册一个事件处理程序比在每个form 元素上注册一个$('form') 更好。
    • 是的,使用委托事件处理程序总是很好,如果您在同一页面上处理多个内容......但如果另一个事件处理程序将停止冒泡,委托事件处理程序将 从不执行 - 不会吗?
    • 我想说的是 - 如果在您的示例中,ID 为 ikki 的表单也有一个事件处理程序,但这会停止事件链(e.stopImmediatePropagation()),那么您的委托事件处理程序仍将不执行
    • 是的,我明白你的意思,解决方案是首先注册“通用”处理程序(正如你所建议的那样)。但是,我还没有看到有人使用e.stopImmediatePropagation()
    【解决方案4】:

    我之前遇到过几次这个问题,我的解决方案是捕获所有表单节点并将它们与特殊操作相关联。这可能不实用,但对您来说也是一种可能的解决方案。

    示例

    //Getting all form elements 
    
    var formNodes = document.getElementsByTagName('form');
    
    //loop through nodelist and add submit event and special class to each. 
    
    for(var i = 0; i < formNodes.length; i++){
    
      formNodes[i].addEventListener('submit'  , registerAction)
      formNodes[i].className += "form-" + i;
    }
    
    
    /*This function captures the submitted form and determines 
    the action to carry out based off class name .
    e.preventDefault will stop page from reloading in case of
    making ajax requests.
    */
    
    function registerAction(e){
      e.preventDefault();
    
      var formTarget = $(e.target).attr('class');
    
     switch(formTarget){
    
       case "form-0" :
         // Do something ...
    
         break;
       case "form-1" :
         // Do something else...
         break;
    
       default:
         break;
    
    
     }
    
      return false;
    }
    

    请记住,registerAction 中的逻辑可以根据您的需要进行更改 在这种情况下,我使用了“case statement”,因为我觉得它最有意义。

    这并不完美,但我希望它能给你一个想法..

    【讨论】:

      【解决方案5】:

      问题是,例如,如果一个表单上有一个 ajax 脚本,它 被我的附加脚本代码阻止了。

      不,它没有。您可以在一个元素上绑定多个处理程序。

      对于极少数情况,请参阅其他建议,但如果我没听错,您的基本假设是在元素上绑定处理程序会取消前一个处理程序。好吧,它没有。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-12
        • 1970-01-01
        • 1970-01-01
        • 2014-10-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多