草庐IT

javascript - 输入类型="submit",onclick处理程序调用this.form.submit(),并且不返回任何值

coder 2024-12-27 原文

编辑:在考虑回答问题之前,请仔细阅读问题的所有内容。我既不是在生产代码中使用内联事件处理程序的可取性,也不是在实现我所引用的文章所 promise 的结果的最佳方法。这是关于Javascript语义和浏览器实现细节的问题,而不是关于最佳编码实践的问题。

听起来像一场噩梦,对吗?

但是我发现一些online advice提倡这样做,以防止再次提交表单:

<input type="submit" 
       onclick="this.disabled=true;
                this.value='Sending, please wait...';
                this.form.submit();" />

撇开对内联事件处理程序的弊端的任何讨论,我在这里看到的问题是:
  • 标签的类型是"submit",因此提交其包含形式是其默认行为;
  • onclick处理程序显式提交包含表单;
  • onclick处理程序不返回false以防止默认行为(请参见1)。

  • 凭直觉,我认为单击此项目将与本文所声称的完全相反-即,两次提交表单,一次是由于显式submit()调用的结果,另一次是由于未抑制的默认行为"submit"类型的控件。

    另一方面,我编写了一个小的PHP脚本(如下所示),并在Firefox和Safari(目前是我唯一方便使用的浏览器)中进行了尝试,并且每次单击按钮仅写入一个日志条目:
    <html>
    <head></head>
    <body>
    <?php
      if (isset($_GET['action']) && $_GET['action'] == 'submit') {
        $s = 'Got form submission at ' . time();
        error_log($s);
        echo $s;
      }
      else {
    ?>
      <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
            method="post">
        <input type="submit" 
               onclick="this.disabled=true;
                        this.value='Sending, please wait...';
                        this.form.submit();" />
      </form>
    <?php
      }
    ?>
    </body>
    </html>
    

    那么,这两种浏览器实际上是在做“正确的”事情吗(其中“正确”是在一些我没有看到或没有足够仔细地阅读的文档中定义的),这意味着我对问题的分析是不完整的或错误的?

    还是我的分析是正确的-意味着观察到的单个提交是浏览器实现者采用特殊情况的逻辑来节省天真的编码者的结果?

    更新:

    为了尝试通过@sourcecode检验声明,form.submit()方法是表单上的某种“第二个提交按钮”,因此要遵循17.13.2 of the HTML4 spec节中所述的规则,即只能有一个“成功”提交按钮,我在PHP测试脚本中添加了一些内容:
    <?php
      if (isset($_GET['action']) && $_GET['action'] == 'submit') {
        $s = 'Got form submission at ' . time() . ', tellme = ' . $_POST['tellme'];
        error_log($s);
        echo $s;
      }
      else {
    ?>
      <form action="http://localhost/~hephaestus/phptests/submittest.php?action=submit" 
            method="post">
        <input type="hidden" id="tellme" name="tellme" value="0" />
        <input type="submit" 
               onclick="this.disabled=true;
                        this.value='Sending, please wait...';
                        this.form.submit();
                        document.getElementById('tellme')=1;" />
      </form>
    <?php
      }
    ?>
    

    在Firefox中,此代码生成单个错误日志条目:

    Got form submission at timestamp, tellme = 1



    这确实表明方法调用已以某种方式被控件的内在事件驱动的行为所取代。

    此外,如果在将return false;的值设置为1之后添加了额外的tellme(从而防止了click事件的传播,从而防止了控件的固有行为),则单个错误日志条目为:

    Got form submission at timestamp, tellme = 0



    表示在这种情况下,提交是调用this.form.submit()的结果。

    另一方面,当我在Safari中尝试相同的两个变体时,每个变体给了我相同的单个错误日志条目:

    Got form submission at timestamp, tellme = 0



    因此,对于Safari而言,方法调用始终优先于事件驱动的提交-大概是因为它发生得更早。

    那是。只是。惊人的。 :-/

    进一步更新:我有机会在Windows NT 5.1的IE 8.0上对此进行测试。

    IE 8反射(reflect)了Safari的行为,即form.submit()方法始终优先于偶数驱动的提交。

    尽管今天几乎没有关系,但我也意识到我在运行OS X 10.4.11的更古老的PowerPC iMac上安装了古老的IE 5.22。有趣的历史琐事是IE5的与IE8的恰好相反:事件驱动的提交始终会取代form.submit()方法-即使click事件在末尾被return false;禁止传播onclick处理程序! (不过,我还没有深入研究这是错误还是功能。我尚未-可能永远不会!-运行测试以确定它是在破坏事件抑制能力,还是试图做一些“聪明的事情”。 “。)

    尽管如此,无论不一致如何,两个IE都只提交一次。

    我的初步结论(到目前为止,实际上是非常坚定的)结论是,“提交”类型的控件与DOM form.submit()方法之间的确切关系还没有很好地定义,并且浏览器实现者在没有任何明确指导的情况下,通常会尽其所能(例如,参见@Boris Zbarsky's answer)。

    至少在Firefox,Safari和IE的情况下,他们的实现者预见到事件和方法调用可能竞争提交同一表格的可能性,并采取了一些步骤(尽管有所不同-基本上是在色域上进行)以确保他们中只有一个会成功。

    (我仍然欢迎来自其他人的其他答案,这些人知道不同的浏览器内部知识足以发表评论,或者使用除我测试过的浏览器以外的其他浏览器加载了我的简单PHP脚本。)

    最佳答案

    Gecko(Firefox)当然会检测到多个提交,并在出现新提交时取消较旧的提交。请参阅http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.h中的mPendingSubmisson成员,以及http://hg.mozilla.org/mozilla-central/file/c4abfca219e5/content/html/content/src/nsHTMLFormElement.cpp中对其的处理(例如nsHTMLFormElement::SubmitnsHTMLFormElement::PostHandleEvent(后者是从提交控件的默认操作 Material 中调用的名称))。

    就规范说的而言,我尚不清楚规范是否一定是理智的,但它存在于http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#concept-form-submit中,并暗示两种提交都会发生,但是由于“导航”的内部细节,后者可能有效地取消了较早的提交。算法。我提交了https://www.w3.org/Bugs/Public/show_bug.cgi?id=20580来整理规范。

    关于javascript - 输入类型="submit",onclick处理程序调用this.form.submit(),并且不返回任何值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14179769/

    有关javascript - 输入类型="submit",onclick处理程序调用this.form.submit(),并且不返回任何值的更多相关文章

    1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

      我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

    2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

      我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

    3. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

      我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

    4. ruby - 如何指定 Rack 处理程序 - 2

      Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

    5. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

      为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

    6. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

      我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

    7. ruby-on-rails - rails : How to make a form post to another controller action - 2

      我知道您通常应该在Rails中使用新建/创建和编辑/更新之间的链接,但我有一个情况需要其他东西。无论如何我可以实现同样的连接吗?我有一个模型表单,我希望它发布数据(类似于新View如何发布到创建操作)。这是我的表格prohibitedthisjobfrombeingsaved: 最佳答案 使用:url选项。=form_for@job,:url=>company_path,:html=>{:method=>:post/:put} 关于ruby-on-rails-rails:Howtomak

    8. ruby - Infinity 和 NaN 的类型是什么? - 2

      我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

    9. ruby - 检查方法参数的类型 - 2

      我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

    10. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

      我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

    随机推荐