ここに、人々が問題をよりよく理解してトラブルシューティングするのに役立つかもしれないいくつかの例があります。
TL; DR
on*
イベントハンドラー(onclick
ボタン要素の属性など):イベントをキャンセルするにはfalseを返します
addEventListener
は別のAPIであり、戻り値(例false
)は無視されます:use event.preventDefault()
。
onclick="<somejs>"
<somejs>
onclick関数の本体にラップされているため、独自の潜在的な混乱があります。
- ブラウザのdevtoolsAPIを使用して
getEventListeners
、イベントハンドラが期待どおりに動作しない場合に、イベントリスナーがどのようにトラブルシューティングするかを確認します。
例
この例はclick
、<a>
リンク付きのイベントに固有です...ただし、ほとんどのイベントタイプに一般化できます。
js-some-link-hook
モーダルを開き、ページナビゲーションが発生しないようにするクラスのアンカー(リンク)があります。
以下の例は、MacOSMojaveのgooglechrome(71)で実行されました。
大きな落とし穴の1つonclick=functionName
は、それが使用するのと同じ動作であると想定することです。addEventListener
javascriptが有効になっているときにjavascriptで処理するアンカータグ(リンク)があるとしましょう。クリックされたときにブラウザがリンクをたどらないようにします(「デフォルトを防ぐ」動作)。
<a href="https://www.example.com/url/to/go/to/when/no/javascript"
class="js-some-link-hook">click me!</a>
onclick属性
function eventHandler (event) {
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);
...そしてあなたが見る:
function onclick(event) {
function eventHandler (event) {alert('eventHandler ran'); return false;}
}
これはまったく機能しません。onclick=
ハンドラー関数を使用する場合、別の関数にラップされます。
関数参照を呼び出さずに指定したため、関数定義が含まれているが呼び出されていないことがわかります。つまり、要素がクリックされたときに実行されていることを確認する必要はありonclick="functionName()"
ません。onclick="functionName"
functionName
さらに、関数が呼び出されて関数がfalseを返した場合でも、関数はonclick
そのfalse値を返さないことがわかります。これはイベントを「キャンセル」するために必要です。
これを修正するために、がからの戻り値(false)を返すonclick
ことreturn myHandlerFunc();
を保証するように設定できonclick
ますmyHandlerFunc
。
return false;
frommyHandlerFunc
を削除して、onclick
toを変更することもできmyHandlerFunc(); return false;
ますが、ハンドラー関数でロジックをまとめたい場合があるため、これはあまり意味がありません。
onclick
javascriptで設定onclick
する場合、(私の例のように)javascriptではなくhtmlで直接設定する場合、onclick
属性値は文字列型であり、すべてが機能することに注意してください。onclick
javascriptを使用して設定する場合は、タイプに注意する必要があります。あなたが言うならelement.setAttribute('onclick', myHandlerFunc())
myHandlerFunc
、今すぐ実行され、結果はクリックごとに実行されるのではなく、属性に保存されます。代わりに、属性値が文字列として設定されていることを確認する必要があります。 element.setAttribute('onclick', 'return myHandlerFunc();')
これがどのように機能するかを確認したので、コードを変更して必要な処理を実行できます。説明のための奇妙な例(このコードは使用しないでください):
function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', 'return ('+eventHandler+')(event);');
}
addEventListenerToElement();
eventHandler関数の定義を文字列にラップしたことがわかります。具体的には、先頭にreturnステートメントがある自己実行関数です。
再びchromedevtoolsコンソールで:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
...ショー:
function onclick(event) {
return (function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
})(event);
}
...そうそう、それはうまくいくはずです。案の定、リンクをクリックするとアラートが表示され、アラートを閉じるとページがどこにも移動したり更新されたりしません。
onclick
...に関するもう1つの注意事項event
イベント時にパラメータを受信して利用する場合は、「イベント」という名前であることに注意してください。名前を使用してハンドラー内でこれにアクセスできますevent
(親onclick
関数スコープから利用可能)。またはevent
、パラメーターとして受け取るハンドラーを作成することもできます(テストに適しています)...たとえばonclick="return myEventHandler(event);"
、前の例のように。
addEventListener
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
ブラウザdevtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
結果:
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
だからあなたはすでに違いを見ることができます。ではaddEventListener
、私たちは中に包まれていないonclick
機能。ハンドラーはevent
パラメーターを直接受け取ります(したがって、必要に応じて呼び出すことができます)。また、return false
ここでは「トップレベル」にあり、のようにreturnステートメントを追加することを心配する必要はありませんonclick
。
したがって、動作するはずです。リンクをクリックすると、アラートが表示されます。アラートを閉じると、ページがナビゲート/更新されます。 つまり、falseを返すことによってイベントがキャンセルされなかった。
仕様を検索すると(下部のリソースを参照)、addEventListenerのコールバック/ハンドラー関数が戻り値の型をサポートしていないことがわかります。必要なものは何でも返すことができますが、ブラウザのAPI /インターフェースの一部ではないため、効果はありません。
解決策:...のevent.preventDefault()
代わりに使用するreturn false;
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
ブラウザdevtools..。
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
与える...
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
...予想通り。
再テスト:
- リンクをクリックします。
- アラートを取得します。
- アラートを閉じます。
- ページのナビゲーションや更新は行われません...これが私たちが望んでいることです。
したがって、falseを返すaddEventListener
ように使用event.preventDefault()
しても、何も起こりません。
リソース
html5仕様(https://www.w3.org/TR/html5/webappapis.html#events)は、例と例の両方を使用してonclick
おりaddEventListener
、次のように言っているため、混乱を招きます。
イベントハンドラHおよびイベントオブジェクトEのイベントハンドラ処理アルゴリズムは次のとおりです。
..。
- 戻り値を次のように処理します。
..。
戻り値がWebIDLブール値のfalse値である場合は、イベントをキャンセルします。
その意味すると思わそれはそうreturn false
両方のイベントをキャンセルaddEventListener
してonclick
。
しかし、それらのリンクされた定義を見ると、次のようになりevent-handler
ます。
イベントハンドラには名前があり、常に「on」で始まり、その後に対象のイベントの名前が続きます。
..。
イベントハンドラーは、2つの方法のいずれかで公開されます。
すべてのイベントハンドラーに共通する最初の方法は、イベントハンドラーのIDL属性としてです。
2番目の方法は、イベントハンドラーのコンテンツ属性としてです。HTML要素のイベントハンドラーとWindowオブジェクトの一部のイベントハンドラーは、この方法で公開されます。
https://www.w3.org/TR/html5/webappapis.html#event-handler
したがってreturn false
、イベントのキャンセルは実際にはonclick
(または一般的にon*
)イベントハンドラーにのみ適用され、addEventListener
異なるAPIを持つ経由で登録されたイベントハンドラーには適用されないようです。
addEventListener
APIはhtml5仕様(on*
イベントハンドラーのみ)でカバーされていないため、on*
例のスタイルイベントハンドラーに固執していれば混乱は少なくなります。