web-dev-qa-db-ja.com

event.preventDefault()vs. falseを返す(jQueryなし)

event.preventDefault()return falseが同じかどうか疑問に思いました。

一部のテスト を実行しましたが、

  • たとえば、イベントハンドラーが古いモデルを使用して追加された場合

    elem.onclick = function(){
        return false;
    };
    

    次に、return falseは、event.preventDefault()などのデフォルトのアクションを防止します。

  • たとえば、addEventListenerを使用してイベントハンドラーを追加する場合

    elem.addEventListener(
        'click',
        function(e){
            return false;
        },
        false
    );
    

    次に、return falseはデフォルトのアクションを妨げません。

すべてのブラウザはこのように動作しますか?

event.preventDefault()return falseにはさらに違いがありますか?

場合によってはreturn falseevent.preventDefault()のように振る舞うことに関するいくつかのドキュメントを見つけることができます(MDNではできませんでした)。


私の質問は、jQueryではなくプレーンなJavaScriptのみに関するものなので、両方の質問のタイトルがほぼ同じであっても、 event.preventDefault()vs. return false の重複としてマークしないでください。

78
Oriol

W3Cドキュメントオブジェクトモデルイベント仕様 in1.3.1。イベント登録インターフェイスは、EventListenerのhandleEventに戻り値がないことを示しています。

handleEventこのメソッドは、EventListenerインターフェイスが登録されたタイプのイベントが発生するたびに呼び出されます。 [...]戻り値なし

1.2.4。イベントのキャンセルドキュメントには、

キャンセルは、イベントのpreventDefaultメソッドを呼び出すことで実行されます。イベントフローのいずれかの段階で1つ以上のEventListenersがpreventDefaultを呼び出すと、デフォルトアクションがキャンセルされます。

どのブラウザでもtrue/falseを返し、event.preventDefault()を使用する可能性のある効果を使用しないようにする必要があります。

更新

HTML5仕様は、実際には、異なる戻り値の処理方法を指定しています。 HTML仕様のセクション7.1.5.1

戻り値がWebIDLブールfalse値の場合、イベントをキャンセルします。

「マウスオーバー」イベント以外のすべてのために。

結論

古い仕様、つまり古いブラウザと互換性があるため、ほとんどのプロジェクトでevent.preventDefault()を使用することをお勧めします。 Edgeブラウザの切断のみをサポートする必要がある場合にのみ、falseを返してキャンセルします。

50
Thorben Croisé

以下は、人々が問題をよりよく理解し、トラブルシューティングするのに役立つかもしれないいくつかの例です。

TL; DR

  • onclickをHTMLマークアップで直接使用する場合、またはsetAttribute('onclick'...)を介して使用する場合、onclick=の内容がonclick関数にラップされるため、実際に戻ることを確認するという点で落とし穴があります。
  • onclickを使用する場合、onclick関数がfalseを返すことを確認してイベントをキャンセルできます...関数がラップされます...したがって、onclick="return myHandler();"またはonclick="myHandler(); return false;"などを実行して、onclickがfalseを返すようにする必要があります。
  • addEventListener ...を使用する場合、falseを返すことは効果がありません。仕様のインターフェースでは、戻り値の型はvoidになっています。代わりにevent.preventDefault()を使用してください。
  • ブラウザのdevtools getEventListeners APIを使用して、イベントリスナーがどのように見えるかを確認して、推測を避け、イベントハンドラーが期待どおりに動作していないかどうかを確認できます。

この例は、<a>リンクを持つclickイベントに固有のものですが、ほとんどのイベントタイプに一般化できます。

クラスjs-some-link-hookのアンカー(リンク)があり、モーダルを開き、ページナビゲーションが発生しないようにします。

以下の例は、MacOS Mojaveのgoogle chrome(71)で実行されました。

1つの大きな落とし穴は、onclick=functionNameaddEventListenerを使用するのと同じ動作であると想定していることです。

onclick属性

function eventHandler (event) {
    // want to prevent link navigation
    alert('eventHandler ran');
    return false;
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.setAttribute('onclick', eventHandler);
}
addEventListenerToElement();

次に、ブラウザーのdevtoolsコンソールで実行します。

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
    console.log(''+listener); // to avoid truncation of output

...そしてあなたが見る:

function onclick(event) {
function t(n){return alert("eventHandler ran"),!1}
}

これはまったく機能しません。 onclick=を使用する場合、ハンドラー関数は別の関数にラップされます。この場合、関数定義は含まれていますが、呼び出されずに関数参照を指定したために呼び出されていないことがわかります。さらに、関数が呼び出されて関数がfalseを返したとしても、onclick関数はそのfalse値を返さないことがわかります。これはイベントを「キャンセル」するために必要です。動作させるには、return myHandlerFunc();をonclick関数でラップする必要があります。

これがどのように機能するかがわかったので、コードを変更して、必要な処理を実行できます。説明のための奇妙な例(このコードは使用しないでください):

function eventHandler (event) {
    // want to prevent link navigation
    alert('eventHandler ran');
    return false;
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.setAttribute('onclick', 'return ('+eventHandler+')();');
}
addEventListenerToElement();

EventHandler関数の定義を文字列にラップしたことがわかります。具体的には、先頭にreturnステートメントがある自己実行関数。

再びchrome devtoolsコンソールで:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
    console.log(''+listener); // to avoid truncation of output

...ショー:

function onclick(event) {
return (function t(e){return alert("eventHandler ran"),!1})();
}

...そう、それはうまくいくはずです。 return false(ミニフィケーションの実行のため、!1、申し訳ありません)。確かに、リンクをクリックするとアラートが表示され、ページを移動したり更新したりすることはありません。

addEventListener

function eventHandler (event) {
    // want to prevent link navigation
    alert('eventHandler ran');
    return false;
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();

ブラウザー開発ツール:

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
    console.log(''+listener); // to avoid truncation of output

結果:

function e(n){return alert("eventHandler ran"),!1}

だからあなたはすでに違いを見ることができます。 onclick関数にラップされていません。したがって、return false(縮小のためreturn !1)はここの最上位にあり、以前のように余分なreturnステートメントを追加することを心配する必要はありません。

動作するはずです。リンクをクリックすると、アラートが表示されます。アラートを閉じると、ページがナビゲート/更新されます。 ieイベントはfalseを返すことでキャンセルされませんでした。

仕様を検索すると(下のリソースを参照)、addEventListenerのコールバック/ハンドラー関数は戻り値の型をサポートしていないことがわかります。必要なものは何でも返すことができますが、インターフェイスの一部ではないため、効果はありません。

解決策:return false;の代わりにevent.preventDefault()を使用しています...

function eventHandler (event) {
    // want to prevent link navigation
    event.preventDefault();
    alert('eventHandler ran');
}

function addEventListenerToElement () {
    var link = document.querySelector('.js-some-link-hook');
    link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();

ブラウザ開発ツール...

var el = document.querySelector('a.js-some-link-hook'),
        listener = getEventListeners(el).click[0].listener;
    console.log(''+listener); // to avoid truncation of output

与える...

function n(e){e.preventDefault(),alert("eventHandler ran")}

...予想通り。

テスト:アラートを取得します。アラートを閉じます。 Noページナビゲーションまたは更新...これが必要です。

資源

Html5仕様( https://www.w3.org/TR/html5/webappapis.html#events )は、例でonclickaddEventListenerの両方を使用し、次のように言っているため、物事を混乱させています。

イベントハンドラーHおよびイベントオブジェクトEのイベントハンドラー処理アルゴリズムは次のとおりです。

...

  1. 次のように戻り値を処理します。

...

戻り値がWeb IDLブールfalse値の場合、イベントをキャンセルします。

したがって、return falseaddEventListeneronclickの両方のイベントをキャンセルすることを意味するようです。

しかし、リンクされたevent-handlerの定義を見ると、次のように表示されます:

イベントハンドラには名前があり、常に「on」で始まり、その後に対象となるイベントの名前が続きます。

...

イベントハンドラは、2つの方法のいずれかで公開されます。

すべてのイベントハンドラーに共通する最初の方法は、イベントハンドラーIDL属性としての方法です。

2番目の方法は、イベントハンドラーのコンテンツ属性としてです。 HTML要素のイベントハンドラーとWindowオブジェクトのイベントハンドラーの一部は、この方法で公開されます。

https://www.w3.org/TR/html5/webappapis.html#event-handler

したがって、イベントをキャンセルするreturn falseは、実際にはonclick(または一般にon*)イベントハンドラーにのみ適用され、異なるAPIを持つaddEventListenerを介して登録されたイベントハンドラーには適用されないようです。 addEventListener APIはhtml5仕様ではカバーされておらず、on*イベントハンドラーのみが対象であるため、例でそれにこだわって違いを明確に示した場合、混乱が少なくなります。

1
mattpr