JavaScriptのイベントハンドラ設定再考
[Think IT] 第1回:そろそろ本気で学びませんか? (1/3)に、
本気でやるならonclick属性は避けてライブラリを活用すべきが書かれていました。
そこに私は
こうやってるんですけど、ページの読み込みが遅い時
イベントハンドラが設定される前に押してhrefの方に遷移されてしまったりしません?
本当は関数もheadに書いてonxxx属性通した方がユーザーには優しいんじゃないかと思わないでもない今日この頃。
と言うコメントを付けたわけですが、そこのところをもう少し追ってみようと思います。
結構長くなってしまったこともあり、説明はあまり丁寧ではないのでわかりづらかったらごめんなさい。
語るべき項目が幾つかあってちょっと発散気味なのですが、第二回が書けたら良いなと思います。
>twkさん
たしかにそういう状況が発生しうる危険性は十分にあると思います。
でもそれはHTMLの組み方に問題がある場合がほとんどで、たとえばHTMLの途中に処理の重いJavaScriptが組み込まれていたりと、何かしらの理由が存在しています。
こういった部分を解消したり、他には、どうしても重要な部分については
YAHOO.util.Event.onContentReady という関数を利用したり、jQueryならready()で、documentではなく、要素を指定することで、特定の要素が現れた段階でイベントハンドラを設定できるので、そのような実装をしてみるのもいいかもしれません。ちなみに記事の例はscriptを全てhead内で記述した場合の例です。
ライブラリを用いないで上の関数のような動作を実装したい場合はhead内に関数をかき、その要素直下にscriptを書いてやるといいかと思います。
に沿って、実際どのような場合に問題があって、どのような方法で回避できるのかをサンプルを作って見てみようと思います。
サンプルは別ウインドウででも開いてみてください。
サンプル
サンプルのソース
サンプルでは、リンクをクリックするとページが再読込されるだけですが、
JavaScriptイベントが設定されている場合には、画面の背景色を黒色にして、ダイアログを表示してから再読込が行われます。
このページの読み込みは意図的に遅くしています。
ページ自体の読み込みと、参照している画像およびJavaScriptの読み込みのいずれも遅くなっています。
また、ページの読み込み中は背景色は水色ですが、onloadイベントで背景色を白色に設定し直しています。
イベント設定の仕方によっては、背景色が白色の時には動作するけれど、水色の時には動作しない、と言う状況が起きることを想定しています。
さて、前置きが長くなりましたが、5つのリンクへのイベント設定の方法です。
一つめは、私がメインで使っているdojo toolkitのイベント設定の方法を使っています。
dojo.addOnLoadでdojo.connectを呼び出しています。
二つめは、jQueryでの記述ですが、HolyGrailさんの
ready()で、documentではなく、要素を指定することで、特定の要素が現れた段階でイベントハンドラを設定できるので
を模しているつもりです。jQueryは使っていないので書き方が違ったらごめんなさい。
三つ目もjQueryを使っていますが、同じくコメントにありました
head内に関数をかき、その要素直下にscriptを書いてやる
を模しています。
四つ目、五つ目はonclickに設定しています。
四つ目はhead内に関数をかき、onclickからそれを呼び出しているのに近い形です。
五つ目は関数自体はbodyの一番下に書いてあります。これは、Yahoo!がパフォーマンス上JavaScriptは下に書いた方が良いよね、
と言っているのと近い形です。
さて、気になる幾つかのブラウザーでの動作結果ですが、下記のようになりました。
| 方法 | 読み込み中にクリック | onload後 |
|---|---|---|
| dojo addOnLoad | × | ○ |
| jQuery ready() | × | ○ |
| jQuery 要素直下にscript | ○ | ○ |
| onclick | ○ | ○ |
| onclick イベントを後から設定 | ○※ | ○ |
※設定前は別の処理ができるのでここは問題ないものとしています
このサンプルhtml上は、
htmlで時間が掛かっている部分についは、全て読み込みが終わってからブラウザーに表示が行われました。
また、imgに時間が掛かった場合は読み込みを並行していました。
問題になるのはHolyGrailさんも仰っているように、scriptタグです。
scriptタグの読み込み中には、それ以前の内容は先に画面に表示され、それ以降の内容はscriptを読み終わるまで表示が停止しました。
この間にリンクをクリックした場合に、ready()を含めた幾つかの方法ではイベントが実行されなくなってしまいます。
これはたとえばHTMLの途中に処理の重いJavaScriptが組み込まれていたりと、何かしらの理由が存在しています。
なのですが、外部のブログパーツやアクセス解析を使っているような場合を考えると、必ずしも自分で解消できない場合があると思います。
例えばGoogle AdsenseやGoogle Analyticsなど。
要素直下にscriptを書く方法は、jQueryでなくてもできますが、当初のhtmlが汚くなってしまう問題、
html的に要素内にscriptタグを書くのは良くない問題、
イベントの種類 (ループとか) によってはこのように書きづらい問題
があると思います。
と言うわけで、四番目五番目にあるような、htmlには全箇所共通のonclickを書いて、
イベントのディスパッチをその中で行う、と言うような方式もありなのではないかな、と思いました。
このクラスは今回適当に書いたので、まだ問題もありますが、そこは改善していけるのではないかと感じました。
と言うかこんなライブラリーがあれば良いんじゃないかな、と思いました。
次の話題です。
sharpoonさんのコメントで、onclick=”関数名()”がid=”ID名”となっているだけで、コードのインターフェース部分とHTML部分がなんらかの規約に基づいて結合していることには変わらない
と言う意見もその通りだな、と思います。
デザイナーは、本当はデザインのためにクラスを調整したりidを調整したりしたい、
と言うのも、クラスやidは多ければ良いわけではなくて、少ない方がcssの見通しも良くなるから、
なのですが、JavaScriptでイベントが設定されているかもしれないと思うと、自由にクラスやidをいじれなくなってしまうのです。
なので、この要素にはJavaScriptイベントが設定されているぞ、と言うのが分かるようになっていた方が
デザイナーも嬉しいケースがあるのではないかと思われます。
とは言え、ループでイベントを設定するケース
もあるので、問題が完全に解消するわけではありませんが。
私は最近プログラマーとデザイナーと完全に並行作業してはいないので、ここら辺が限界なのかなと思いますが、うまい策はあるのでしょうか?
次いで、onclickと本気とIEのところである中クリックや見映えの問題について。
私も中クリックしてしまった、と閉じてしまったり、いわゆる中クリックしても何も起きなかったことがしばしばあります。
ここでの問題の一つは、イベントを設定するような要素をリンクぽい見映えにするべきか他の見映え(例えばボタンぽく)にするべきか、について。
gmailなんかはリンクに似せていますよね(中クリックしても何も起きない)。
どこがクリックできるのかもよく分からない初級者に取っては、恐らくリンクぽい見映えがベストなのでしょう。
また、ボタンの場合、デフォルトのフォームのボタンに近づけると、見映えが(多くの人にとっては許容したくないくらい)悪くなりますし、
平面的な見映えにすると、これは実はリンクで中クリックできるのではないか、と言うことになってしまいます。
もう一つは、イベントを設定するような要素にaタグを使うかどうかについて。
aタグを使うのは、スタイル設定が面倒なのもありそうですが、
aタグでないと:hoverが使えないブラウザーもあるので、そこで楽をしていると言うのは意外と大きいと思います。
手抜きするなよ、と言われそうですが、:hoverの代わりのJavaScriptが簡単に書けるデザイナーはそれほど多くないと思います。
ちょっと言い訳じみていますが、ブラウザーがバージョンアップしていけば、aタグが使われるのは減るかも知れません。
