(リスト1)。
検索フォーム
検索キーワードを入力するためのテキストボックスと、検索を実行する「検索」ボタンを作ります(リスト2)。
id=frmSearchとしてform要素を定義します。検索を実行する「検索」ボタンを作ります。ここは前回と変わりませんね。
検索履歴
検索履歴を表示する領域です(リスト3)。
id=historyとしてdiv要素を定義します。
「検索履歴」というタイトルと、検索履歴を消去するid=clearのa要素「クリア」を定義します。
また、履歴のリストを保持するul要素を定義します。
検索結果
検索結果を表示する領域です(リスト4)。
id=viewとしてdiv要素を定義します。
「ビデオ」というタイトルと、並び替えのための4つのa要素を定義します。
サムネイル画像を表示する領域を、id=videosとしてdiv要素を定義します。
ページングを行う「前へ」「次へ」リンクとページング情報を表示するフッタを、id=footerとしてdiv要素を定義します。
以上で、画面の定義は終わりです。jQueryを使うとイベントハンドラの定義が簡単に分離できるため、HTMLがとても見やすいですね。
サンプルの機能拡張(2)
初期化処理
jQueryでページ読み込み時の初期化処理を実装するには、次のように定義するのでしたね。
今回は、イベントハンドラと初期処理を定義します。
イベントハンドラ
検索
検索を実行した時のイベントを定義します(リスト5)。
このsubmitイベントハンドラの書き方は第2回で出てきましたね。
入力されたキーワードを取得し引数として、searchNewメソッドを呼び出します。
今回は、キーワードをそのまま引数にせず、オブジェクトリテラルの形で渡しています。
プロパティkeyword
に入力されたキーワードを値としてオブジェクトリテラルを生成しています。
オブジェクトリテラルの書式はこれまで見たことないですか?第2回で説明したJSONにそっくりですね。
JSONはJavascriptのオブジェクトリテラルから派生したものなので、とても似ています。詳しくは第2回を参照してください。
もし、オブジェクトリテラルの書式以外で記述するには、たとえば次のように書くことになります。
プロパティが増えたら記述が大変そうですね。オブジェクトリテラルの書式を使うとすっきりと記述できるので是非覚えてください。
また、検索後に次の検索キーワードをすぐに入力できるように、select()
メソッドを呼び出して、テキストボックスの文字列を選択状態にしています。
並び替え
並び替えのリンク「関連度」「追加日」「再生回数」「評価」をクリックしたときのイベントを定義します(リスト6)。
4つのリンクのイベントが1つのイベントハンドラで簡潔に定義できてますね。
これがjQueryの面白いところです。
それでは1つずつ解説しましょう。
説明のため、並び替えのリンクのHTMLを抜粋して再掲します(リスト7)。各リンクのidの値には、Youtube APIのorderbyパラメータの値を指定しています。
まず、4つのリンクのjQueryオブジェクトを生成します。
このセレクタは、id=sortで定義される要素の子要素であるa要素を選択しています。
つまり、ここでは4つのa要素をあらわすjQueryオブジェクトを生成しています。
このjQueryオブジェクトに対して、click(fn)メソッドを呼び出すと、これらの4つのリンクをクリックした時のイベントを定義することができます。
クリック時には、orderbyプロパティにa要素のid、pageプロパティに1を持つオブジェクトをsearchHistoryメソッドに渡し呼び出しています。
orderbyプロパティの値の記述に出てきたthis
とは何でしょうか?
この場合はリンクのDOM要素の参照です。jQueryのイベントハンドラのコールバック関数内では、this
はその対象のDOM要素の参照を表します。
たとえば、<a id="relevance">関連度</a>
がクリックされればそのリンクのDOM要素への参照になります。
また、$(this)
とすれば、そのDOM要素のjQueryオブジェクトを生成することもできます。とてもよく使うので覚えてください。
よって、それぞれの並び替えのリンクをクリックすると、そのDOM要素のidプロパティを取得してオブジェクトを作りsearchHistoryメソッドに渡しています。
イレギュラーな使い方ですが、それぞれのidの値にYoutube APIのorderbyパラメータの値を指定しているので、
実際の検索を行うメソッド内では、どのリンクがクリックされたかを判別することも必要ありません。
idの値をそのままorderbyパラメータの値として使うだけです。
また、今後並べ替えのリンクが増えても、イベントハンドラの実装に手を加える必要がありません。
このようにjQueryを使うと非常にすっきりとした実装ができます。
前へ
「前へ」リンクをクリックしたときのイベントを定義します(リスト8)。
まず、現在のページ数が1以下の場合は前のページがないので、処理を終了しています。ページ数は1から始まる数値としました。
ここで出てくるsearchCondオブジェクトは、現在の検索条件を保持するグローバルなスコープのオブジェクトです。
pageプロパティが検索条件のページ数を保持します。
グローバルスコープで次のように、定義しました。
このように適当にグローバルスコープにオブジェクトを作ったり、メソッドを定義すると、名前空間がどんどん汚れていやな感じですね。
これを回避した実装は次回説明します。
そして、現在の検索条件のページ数から1を減算してsearchHistoryメソッドを呼び出しています。
次へ
「次へ」リンクをクリックしたときのイベントを定義します(リスト9)。
まず、次ページのビデオのインデックスが検索結果件数よりも多くなる場合は、処理を終了しています。
そして、現在の検索条件のページ数から1を減算してsearchHistoryメソッドを呼び出しています。
VIEW_COUNTは1ページに表示する数です。次のように定義しました。
また、searchCondオブジェクトのtotalプロパティは、検索結果件数を保持します。
クリア
検索履歴にある「クリア」リンクをクリックしたときのイベントを定義します(リスト10)。
検索履歴を保持するリスト$("#history > ul")
、ビデオのサムネイルを表示する$("#videos")
、検索結果件数を表示する$("#result")
のそれぞれの要素に対してempty()
メソッドを呼び出し、子要素を削除しクリアしています。
初期処理
ページが読み込まれたときに、検索テキストボックスをフォーカスし、すぐに検索キーワードを入力して検索できるようにしましょう。
サンプルの機能拡張(3)
新規検索
新規検索時の処理を定義します(リスト12)。ここで新規検索とは、検索履歴に存在しないキーワードで検索した場合を指します。
検索キーワードを表すkeywordプロパティに、引数のオブジェクトのkeywordプロパティを設定しています。
また、新規検索時にはページ数を1、並べ替えを関連度(relevance)、fromHistoryフラグ(履歴検索かどうか)をfalseに指定しています。
そして、その検索条件オブジェクトを引数にsearchメソッドを呼び出しています。
履歴検索
履歴検索時の処理を定義します(リスト13)。ここで履歴検索とは、検索履歴からの検索、または、検索結果の並べ替えを指します。
まず、検索履歴が無い場合は処理を終了しています。
検索を実行すると、次の履歴リストへ検索内容を保持します。
$("#history li")
とすることで、履歴リスト内のli要素を走査し、jQueryオブジェクトを生成しています。
size()
メソッドは、jQueryオブジェクトのDOM要素数を返すので、返り値が0かどうかを判別すれば履歴が存在するかどうかが分かります。
そして、検索条件オブジェクトを生成し、searchメソッドを呼び出しています。
$.extend()
メソッドは、オブジェクトを拡張するjQueryのユーティリティメソッドです。書式は次のようになります。
targetは拡張されるオブジェクトを指定します。
その後ろには、拡張元のオブジェクトをいくつでも引数に指定できます。
拡張元のオブジェクトに同じプロパティが存在した場合は、右に指定したオブジェクトのプロパティの値で上書きされます。
ここでは、検索条件を保持するsearchCondオブジェクトを元に、引数で与えられた検索条件condと、fromHistoryフラグ(履歴検索かどうか)をtrueに指定して拡張した、新しい検索条件オブジェクトを生成しています。
検索
引数の検索条件オブジェクトを元に、検索を実行する処理を定義します(リスト14)。
基本的な構造は第2回のものと変わりません。よって、jQueryのDOM操作部分を抜粋して説明します。
サムネイルを生成
サムネイルのDOMの構成は次のようになります。
対応するjQueryの実装部分を再掲します(リスト15)。
ソースコードを見ただけで、図2のどの部分を実装しているか一目で分かるのではないでしょうか。
また、この実装部分は、実際は1行です。
とても簡潔に記述できますね。
まず、サムネイルのdiv要素を生成します。class属性にthumbnailを指定します(15-(1))。
クラス属性を追加するには、addClass(class)
メソッドをクラス名を引数にして呼び出します。
サムネイルのdiv要素にimg要素を追加します(15-(2))。最後の子要素として追加するには、append(content)
メソッドを追加する要素を引数にして呼び出します。
ここでは、追加するimg要素を次のように生成しています。
attr(key, value)
メソッドは、1番目の引数に属性名、2番目の引数に値を指定して呼び出すと、指定した属性に値を設定します。ここではsrc属性に、サムネイル画像のURLが設定されているgroup.media$thumbnail[0].url
を指定しています。
動画のタイトルを追加します(15-(3))。ここではTEXTノードとしてタイトルをそのまま追加しています。
動画の再生回数を追加します(15-(4))。
ここでは、class属性がinfoのspan要素を生成しています。また、yt$statistics.viewCount
を参照し、動画の再生回数を取得しています。
以上で、DOM要素の構築部分は終わりです。とても簡潔ですね。
次の行からはクリック時のイベントと親要素への追加です。
サムネイルをクリックした時のイベントハンドラを定義します(15-(5))。
今回は、クリック時に新しいウィンドウを開くようにしました。
最後に、このサムネイル要素をid=videosで定義される要素に追加します(15-(6))。
appendTo(target)
メソッドは、追加先の親要素を引数にして呼び出します。
検索履歴に追加
新規検索時に、検索履歴に検索条件を追加します。
検索の内容が分かりやすいように、検索結果の1番目のサムネイル画像と、検索キーワードを表示します。
検索結果の1番目のサムネイル画像を表すjQueryオブジェクトに対してclone()
メソッドを呼び出しています。
こうしないと、img要素そのものが検索履歴領域に追加(つまり移動)してしまいます。
サンプルの機能拡張(4)
検索結果件数表示
右下にある検索結果件数表示を実装します(リスト16)。
検索結果件数と、表示しているサムネイルのインデックス番号を表示します。
このメソッドは、ページに表示されている最初のサムネイルのインデックス番号と、検索結果件数を引数に取ります。
ページに表示されている最後のサムネイルのインデックス番号を計算し、表示します。
text(value)
メソッドは、対象のDOM要素のテキストノードに引数value
の文字列を設定します。
検索履歴
検索履歴機能を実装します。検索履歴機能を再掲します。
検索履歴機能
- 検索を実行すると、検索履歴に履歴が残る。
- 検索キーワードが検索履歴に存在する場合は、その履歴を最上位に移動する。
- 検索履歴には、検索結果の第1番目のサムネイル画像、検索キーワード、削除リンク「[x]」を表示する。
- 検索履歴をクリックすると、その検索キーワードで再度検索する。
- 削除リンク「[x]」をクリックすると、その検索履歴を消去する。
- 「クリア」をクリックすると、全ての検索履歴を消去する。
検索履歴追加
検索履歴に履歴を追加する処理を実装します(リスト17)。
検索履歴の検索
すでに検索履歴に存在する検索キーワードの場合は、その履歴を最上位に移動します。
よって、検索履歴に検索キーワードが存在するかどうかを判別しなければなりません。
次のように検索します。
$.grep(arr, fn)
は、arr
に指定された配列をイテレーションし、コールバック関数fn
がtrueを返した要素で構成される配列を返します。
コールバック関数でarr
をフィルタリングするようなユーティリティメソッドです。
コールバック関数には2つの引数が与えられます。1番目(ここではitem)は配列の要素です。2番目(ここではindex)は要素のインデックス番号です。
イテレーション対象の配列に、li要素を指定しています。
そのli要素の子要素には、検索キーワードを保持するclass属性がkeyのspan要素があります。
この検索キーワードは次のように取得しています。
まず、li要素のjQueryオブジェクトを生成します。
その子要素を選択するために、children(expr)
メソッドを呼び出しています。
children(expr)
は引数のセレクタにマッチする子要素を返すメソッドです。
text()
メソッドを呼び出して、検索キーワードを取得します。
この履歴にある検索キーワードと、検索時の検索キーワードが一致する場合は、そのli要素を返すようにします。
このコールバック関数がtrueを返せばよいので、次のように記述します。
この$.grep(arr, fn)
の実行結果を保持する変数exists
には、検索履歴に検索キーワードが存在した場合、そのli要素を含む配列が返されます。
もし、存在しない場合は、空の配列が返されます。
よって、存在するかどうかを判別するには次のように記述します。
履歴に存在しない場合
サムネイル画像、検索キーワード、削除リンクを含むli要素を追加します。
まず、li要素を生成します。
サムネイルの画像を追加します。この要素は引数imgとして渡されるのでそのまま追加します。
検索キーワードを追加します。class属性がkeyのspan要素を追加します。検索キーワードは引数keywordとして渡されます。
削除リンクを生成します。削除リンクは、class属性がdelのa要素です。[x]という文字にします。
削除リンクをクリックしたときのイベントハンドラを定義します。
クリックすると、その要素が属するli要素を削除します。
イベントハンドラのコールバック関数内では、イベント対象のDOMオブジェクトはthis
で参照できるのでしたね。このDOM要素のjQueryオブジェクトを生成します。
親要素を返すメソッドparent()
を呼び出し、要素が属するli要素を取得します。
そして、remove()
メソッドを呼び出して、その要素を削除します。
また、現在表示されている検索結果が、この削除した検索履歴のものであれば、サムネイル表示領域と検索結果件数表示領域をクリアしなければなりません。
よって、次のように記述します。
これで、削除リンクの実装は終わりです。
次に、この検索履歴をクリックした場合、その検索キーワードで再度検索するようにしましょう。
クリックイベントハンドラを次のように定義します。
検索キーワードを表すkeywordプロパティに、引数のkeywordを設定しています。
また、履歴検索時にはページ数を1、並べ替えを関連度(relevance)に指定しています。
そして、その検索条件オブジェクトを引数にsearchHistoryメソッドを呼び出しています。
最後に、このli要素を、id=historyで定義される要素の子要素ul要素に追加します。
履歴に存在する場合
そのli要素を履歴の先頭に移動し、画像を入れ替えます。次のように実装します。
まず、li要素を、prependTo(target)
メソッドを呼び出して、履歴の先頭に移動します。
この場合の移動先は親要素(変わらない)ので、$(exists).parent()
として親要素を取得します。
最後に履歴の画像を、最新の検索結果の画像で置き換えます。
以上で全ての実装が終了しました。サンプルを実行して動作を確認してみてください。
まとめ
今回はYoutube APIを少し詳しく解説しました。
YouTube Data APIを使ったアプリケーションの開発をする際に参考にしてください。
サンプルの機能を拡張して、jQueryの使い方をより詳しく説明しました。
今回は、数多くのjQueryメソッドが出てきました。
また、jQueryを使った基本的な実装方法も紹介することができました。
jQueryをはじめて使う方は是非参考にしてください。