« 「Amazon ベストセラー ビューア」公開 | メイン | MASHUP AWARD 4th 開催! »

jQueryでダミーフォーカスの実装

昨日公開した「Amazon ベストセラー ビューア」では、左側の商品のサムネイルで、オレンジ色のカーソルを実装しています。キーボードの、hで左に移動、lで右に移動、jで下に移動、kで上に移動します。

今回は、こうしたダミーフォーカスの実装方法を解説します。

とっても、やり方は簡単で、フォーカスを表現するスタイルシートのクラスを定義して、そのクラスを付け外しするだけです。

Amazon ベストセラー ビューア」では、フォーカスを定義するスタイルシートのクラスとして、以下のようなクラスを定義しています。

#feed img{
    padding:3px;
}
#feed img.selected {
    background-color:#FF8C00;
}

id="feed"のエレメント(サイトではdiv)の下にあるimgは、すべてpadding:3pxとし、selectedというクラスが指定されているimgについては、背景がオレンジ色になります。これで、画像の周りにオレンジ色の枠ができ、フォーカスを表現しています。

以下に、上記スタイルを適用したimgを並べてみます。

selectedクラスが指定された2つ目の画像の周りがオレンジ色になっています。

さて、サイトでは、キーボード操作でフォーカスが移動できるようにしています。

これには、先日紹介したjQueryのキーバインドのプラグイン「js-hotkeys」を使っています。

このプラグインでは、キーに対して、動作させたい関数を以下のように割り付けます。

$.hotkeys.add('Ctrl+c', function(){ alert('copy anyone?');});

では、hキーを押すとフォーカスが左に移動するという機能を実装してみます。

「フォーカスが左に移動する」というのは、以下のように書くことができます。

$('#focus_test_000 img.selected').removeClass('selected')
.prev().addClass('selected');

id="focus_test_000"以下のselectedというクラスが指定されたimgタグから、selectedというクラスをremoveして、そのimg属性の前にある要素にselectedクラスを付加しています。

これをhキーに割り付けるので、以下のようなコードになります。

$.hotkeys.add('h',function(){
    $('#focus_test_000 img.selected').removeClass('selected')
    .prev().addClass('selected');
});

では、動きを見てみましょう。以下に、id="focus_test_000"を指定したpタグの中にimg属性を並べて、上記関数を実行してあります。

hキーを押下すると、オレンジ色のフォーカスが左へ移動していきます。

一番左側にある画像にフォーカスがあたっているときに、hキーを押すと、フォーカスが消えてしまいます。

ということで、先ほどの関数に「一番左側にフォーカスがあるときは、最も右側の(最後の)要素にselectedクラスを付加する」という処理を加えてやればOKです。

さて、フォーカスが移動する要素が少ない場合は、このような実装方法で問題ないかと思いますが、要素が多くなってくると動作が遅くなる可能性があります。

というのも、$('#hoge img.selected') と書いた場合、jqueryの内部では、getElementsByTagNamesでid="hoge"要素以下のimgタグを全て取得し、ループを回してclass名のチェックを行っているからです。

キーボード操作のように、連続して関数が実行される場合は、ライブラリ内部で実行される処理もなるべくコンパクトになるよう考えた方が良いです。

で、「Amazon ベストセラー ビューア」では、左側のサムネイル(imgタグが100個)のフォーカス移動については、selectedIdというグローバル変数でフォーカスが当たっている要素のid属性を管理しています。

つまり、以下のように書くことで、内部ではgetElementByIdが2回実行され、先ほどよりも早く処理することができます。

$.hotkeys.add('h',function(){
    $('#img_'+selectedId).removeClass('selected');
    selectedId -= 1;
    $('#img_'+selectedId).addClass('selected');
});

jQueryの魅力であるメソッドチェーン風の書き方を崩す形になりますが、こちらの方が快適に動作します。