JavaScriptの動かないコード (中級編) onKeydownイベントが認識されない
以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)
やりたい事:
- 画面を開いているとき,何かキーボードを押すと,別のページにジャンプする。
<body> 何かキーを押すと,Yahooにジャンプします。 <script language="JavaScript"> function f() { // ジャンプ location.href = "http://www.yahoo.co.jp"; } document.body.onkeydown = f; </script> </body>
不具合の原因
FFでは,body.onkeydown プロパティへ =(イコール)で代入してイベントハンドラを登録しようとすると,「画面へのキー押下」を認識してくれないようだ。
addEventListenerでイベントハンドラを設定した場合も,同様にFirefoxでは認識されない。
ただし,画面への漠然としたキー押下ではなく,「特定の入力要素上のキー押下」ならば認識してくれる。
例えば
<input type=text>
のようにテキストボックスが用意されており,このボックス上にマウスでフォーカスした上で何かキーを押せば,Firefoxでも冒頭のコードで f() が実行される。
また,もしキー押下ではなくクリックの場合なら
// 画面上をクリックするとヤフーにジャンプします… document.body.onclick = f;
これはFirefoxでもIEでもイベントが受理される。
また,もしプロパティへの代入をせずに,bodyタグに属性として記述すれば
<body onKeydown="f()">
これはFirefoxでも正常にキー押下を認識してくれる。
- Firefoxで
- キー押下イベントを
- document.bodyに対して
- プロパティ代入やaddEventListenerで設定して
- 特に何もフォーカスしないでキー押下
した場合のみ,イベントリスナが受理されないのだ。IEでは動くのに。
どう修正すべきか
このエラーは,イベント追加対象の違いから生まれる。
ページ全体にイベントを追加したい場合,document.body ではなく document に追加するべきなのだ。
ページ全体に対するイベントハンドラの登録
http://www.keynavi.net/ja/tipsj/addhp...
ページ全体にイベントハンドラを設定することを考えます。
HTMLで記述する場合、<body onload="処理内容"> などと bodyタグ中に書くのが普通です。
一方、JavaScriptで行う場合 onLoadでは「window.onload=ハンドラ関数;」とするのがもっとも一般的です。
IEではdocument.body=...でも動作します。
上記サイトの一覧表にあるように,
onloadはwindow,
onmousedownはdocument
という風に,イベントの種類ごとにそれぞれ追加対象が異なっているので注意したい。
これによれば,document.body.onkeydown が動作したのは,IEだけの特別な現象。
クロスブラウザで動くようにするためには,bodyを飛ばして
document.onkeydown = f;
とすればよいので,このように書く癖をつけよう。