編集:あなたがそれに答えることを考える前に、質問を通してずっと注意深く読んでください。私は、本番コードでインラインイベントハンドラーを使用することの妥当性について質問していません。また、参照している記事で約束された結果を達成するための最良の方法についても質問していません。これは、Javascriptのセマンティクスとブラウザの実装の詳細に関する質問であり、コーディングのベストプラクティスに関する質問ではありません。
悪夢のようですね。
それでも私は、フォームの二重提出を防ぐためにまさにそのようなことをすることを提唱するいくつかのオンラインアドバイスを見つけました:
<input type="submit"
onclick="this.disabled=true;
this.value='Sending, please wait...';
this.form.submit();" />
インラインイベントハンドラーの悪についての議論はさておき、ここで私が目にする問題は次のとおりです。
- タグのタイプは
"submit"
、であるため、その包含フォームを送信することがデフォルトの動作です。 onclick
ハンドラーは、含まれているフォームを明示的に送信します。- ハンドラーは、デフォルトの動作を防ぐために
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スクリプトをロードした人からの追加の回答を歓迎します。)