6

編集:あなたがそれに答えることを考える前に、質問を通してずっと注意深く読んでください。私は、本番コードでインラインイベントハンドラーを使用することの妥当性について質問していません。また、参照している記事で約束された結果を達成するための最良の方法についても質問していません。これは、Javascriptのセマンティクスとブラウザの実装の詳細に関する質問であり、コーディングのベストプラクティスに関する質問ではありません。

悪夢のようですね。

それでも私は、フォームの二重提出を防ぐためにまさにそのようなことをすることを提唱するいくつかのオンラインアドバイスを見つけました:

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

インラインイベントハンドラーの悪についての議論はさておき、ここで私が目にする問題は次のとおりです。

  1. タグのタイプは"submit"、であるため、その包含フォームを送信することがデフォルトの動作です。
  2. onclickハンドラーは、含まれているフォームを明示的に送信します。
  3. ハンドラーは、デフォルトの動作を防ぐためにonclick戻りません( 1を参照)。false

直感的には、このアイテムをクリックすると、記事の主張とは正反対のことができると思います。つまり、フォームを2回送信し、1回は明示的なsubmit()呼び出しの結果として、もう1回は抑制されていないデフォルトの動作として送信します。"submit"-タイプされたコントロール。

一方、私は小さなPHPスクリプト(以下)を作成し、FirefoxとSafariの両方で試してみました(現時点では、便利に利用できる唯一のブラウザーです)。ボタンをクリックするごとに1つのログエントリしか書き込みません。

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

したがって、これら2つのブラウザは実際に「正しい」ことを行っています(「正しい」とは、私が見たことがないか、十分に読んでいないドキュメントで定義されています)。つまり、問題の分析が不完全または間違っていることを意味します。 ?

または、私の分析は正しいですか?つまり、観察された単一の送信は、ブラウザーの実装者がナイーブなコーダーを自分たちから救うために特別な場合のロジックを入れた結果であるということですか?

アップデート:

form.submit()このメソッドはフォーム上のある種の「2番目の送信ボタン」であるという@sourcecodeによる主張を経験的にテストするために、HTML4仕様のセクション17.13.2に記載されているルールに従う必要があります。 1つの「成功した」送信ボタンで、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では、このコードは単一のエラーログエントリを生成します。

タイムスタンプでフォーム送信を取得しました、tellme = 1

これ、メソッド呼び出しが、コントロールの固有のイベント駆動型動作に何らかの形で取って代わられていることを示唆しています。

return false;さらに、値を1に設定した後に追加を含めるとtellme(これにより、クリックイベントが伝播されなくなり、コントロールの固有の動作が妨げられます)、単一のエラーログエントリは次のようになります。

タイムスタンプでフォーム送信を取得しました、tellme = 0

この場合、送信は。の呼び出しの結果であったことを意味しますthis.form.submit()

一方、Safariで同じ2つのバリエーションを試してみると、それぞれが同じ単一のエラーログエントリを表示します。

タイムスタンプでフォーム送信を取得しました、tellme = 0

したがって、Safariの場合、メソッドの呼び出しは常にイベント駆動型の送信よりも優先されます。おそらく、それが以前に発生したためです。

それです。ただ。素晴らしい。:-/

さらなる更新: WindowsNT5.1のIE8.0でこれをテストする機会を得ました。

IE 8は、Safariの動作を反映しています。つまり、form.submit()メソッドは常に偶数駆動の送信よりも優先されます。

今日はほとんど関係ありませんが、OSX10.4.11を実行しているさらに古いPowerPCiMacに古いIE5.22があることにも気づきました。ここでの歴史的な雑学の興味深い点は、IE5がIE8の動作とは正反対に動作することです。イベント駆動型の送信は、ハンドラーの最後でクリックイベントの伝播が禁止されている場合でも、常にform.submit()メソッドに優先します。(ただし、これがバグなのか機能なのかについては詳しく調べていません。まだ、イベントの抑制を妨げているのか、それとも「スマート」なことをしようとしているのかを判断するためのテストを実行していません。 "。)return false;onclick

それでも、不整合に関係なく、両方のIEは1回の送信のみを実行します。

私の暫定的な(まあ、今では実際にはかなりしっかりしている)結論は、「送信」タイプのコントロールとDOMform.submit()メソッドの間の正確な関係は明確に定義されておらず、ブラウザーの実装者は、明示的なガイダンスがない場合、一般的に、彼らが最もよく考えることを行います(たとえば、 @ Boris Zbarskyの回答を参照してください)。

少なくともFirefox、Safari、IEの場合、それらの実装者は、イベントとメソッド呼び出しの両方が同じフォームを送信するために競合する可能性を予見し、(異なるものではありますが、ほぼ色域を実行している)確実にするための手順を実行しましたそれらのうちの1つだけが成功するだろうと。

(さまざまなブラウザーの内部を十分に理解してコメントできる人、またはテストしたブラウザー以外のブラウザーを使用して単純なPHPスクリプトをロードした人からの追加の回答を歓迎します。

4

4 に答える 4

3

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::Submitand nsHTMLFormElement::PostHandleEvent(後者は送信コントロールのデフォルトのアクションから呼び出されるもの)。

仕様が何を言っているのかという点では、仕様が必ずしも正気であるかどうかは私には明らかではありませんが、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を提出しました。

于 2013-01-06T17:39:28.113 に答える
0

送信のonclickでスクリプトを実行しないでください。また、フォームを送信しないでください。また、ボタンを無効にすると、送信が停止する場合があります。

記事のコードが機能する場合、それは幸運によるものであり、多くのブラウザが、この無効化されたボタンをクリックするだけで、送信ボタンが無効になり、送信イベントが発生するという競合状態に陥ると思います。

これは、どのブラウザでも機能するもののインライン提案です。

<form action="..." method="post" 
 onsubmit="document.getElementById('subbut').innerHTML='Sending, please wait...'">
  <span id="subbut"><input type="submit" /></span>
</form>

そして同じことを目立たないように:

window.addEventListener('load',function() {
  document.getElementById('form1').addEventListener('submit', function(e) {
    document.getElementById('subbut').innerHTML = 'Sending, please wait...';
  })
})
<form action="..." method="post" id="form1">
  <span id="subbut"><input type="submit" /></span>
</form>

于 2013-01-06T07:02:54.093 に答える