今回は、
実装の前に
Suggest機能の実装に入る前に、
スコープを隠蔽する
jQueryにならって、
(function(){
// (1) このスコープは公開されない
var local = ・・・
// (2) 必要なものだけを公開する
window.global = ・・・
})();
無名関数の定義(function(){})と、
Youtubeコンストラクタ関数の定義
Youtubeというコンストラクタ関数を作成し、
(function(){
// コンストラクタ関数の定義
var Youtube = function() {
・・・
}
Youtube.prototype = {
・・・
}
// 名前空間 window.yt に公開
window.yt = new Youtube();
})();
これで、
今回は、
外部ファイル化
さらにこの実装を、
Suggest機能
それでは、
動作イメージ
検索テキストボックスに文字列を入力すると、
![Suggest機能 Suggest機能](/assets/images/dev/feature/01/jquery/0004/thumb/TH400_04_suggest.png)
機能概要
今回実装する機能の要件は次のとおりです。
- 検索テキストボックスに文字列を入力すると、
500ミリ秒後に関連するキーワード (以下 Suggest) を表示する。 - Suggestが表示されていない場合、
検索テキストボックスで 「↓」 を押すとSuggestを表示する。 - Suggestが表示されている場合、
検索テキストボックスで 「↓」 を押すとSuggestにフォーカスを移動する。 - Suggestを選択すると、
検索テキストボックスに選択したSuggestを設定する。 - Suggestをダブルクリックすると、
検索テキストボックスにダブルクリックしたSuggestを設定し、 検索する。 - ESCキーを押すとSuggestを閉じる。
- Suggestがない場合は何も表示しない。
Suggestデータ
Youtube APIにはSuggest用のAPIやデータは用意されていません。
今回は、
Suggestの実装(1)
画面要素
検索テキストボックスの下に、
<!-- 検索フォーム -->
<form id="frmSearch">
<input type="text" id="keyword" size="35">
<input type="submit" value="検索"><br>
<select id="suggest" size="10"></select> <!-- Suggest -->
</form>
イベントハンドラ
検索テキストボックス
検索テキストボックスのイベントを定義します
// 検索テキストボックス
$("#keyword").keyup(function(e){
if (e.keyCode == 27) { // esc
$("#suggest").hide();
} else if (e.keyCode == 40) { // ↓下矢印
if ($("#suggest").is(":visible")) { // suggest が表示されている
$("#suggest").focus()[0].selectedIndex = 0;
$(this).val($("#suggest").val());
} else {
yt.suggest(true);
}
} else {
yt.suggest();
}
});
このイベントハンドラのコールバック関数の引数eには、
$("#keyword").keyup(function(e){
if (e.keyCode == xx) {
// xxが押下されたときの処理
・・・
}
}
まず、
if (e.keyCode == 27) { // esc
$("#suggest").hide();
}
続けて、
} else if (e.keyCode == 40) { // ↓下矢印
if ($("#suggest").is(":visible")) { // suggest が表示されている
$("#suggest").focus()[0].selectedIndex = 0;
$(this).val($("#suggest").val());
} else {
yt.suggest(true);
}
}
それ以外のキーが押下された場合は、
} else {
yt.suggest();
}
Suggestセレクトボックス
Suggestセレクトボックスのイベントを定義します
// Suggestセレクトボックス
$("#suggest")
.change(function(){
$("#keyword").val($(this).val());
})
.keyup(function(e){
if (e.keyCode == 13) { // Enter
$(this).hide();
$("#frmSearch").submit();
} else if (e.keyCode == 27) { // Esc
$(this).hide();
$("#keyword").focus();
}
})
.dblclick(function(){
$(this).hide();
$("#frmSearch").submit();
});
Suggestセレクトボックスの選択項目が変更された場合は、
.change(function(){
$("#keyword").val($(this).val());
})
Enterキー
if (e.keyCode == 13) {// Enter
$(this).hide();
$("#frmSearch").submit();
}
escキー
} else if (e.keyCode == 27) { // Esc
$(this).hide();
$("#keyword").focus();
}
Suggestセレクトボックスがダブルクリックされた場合は、
.dblclick(function(){
$(this).hide();
$("#frmSearch").submit();
});
初期処理
ページが読み込まれたときには、
// --- 初期処理 ---
// ページロード時は suggest を隠す
$("#suggest").hide();
Suggestの実装(2)
Suggestの実行
Suggest処理を実行し、
// --- suggest実行 ---
suggest: function(force) {
this.stop_suggest();
if (force) this.preinput = null;
this.tid = setTimeout(function(){yt.do_suggest()}, Youtube.SUGGEST_TIME);
},
まず、
this.stop_suggest();
引数forceがtrueであれば、
if (force) this.preinput = null;
Suggest処理を実行します。
ただ、
this.tid = setTimeout(function(){yt.do_suggest()}, Youtube.SUGGEST_TIME);
Youtube.
Youtube.SUGGEST_TIME = 500; // Suggestまでの時間(ミリ秒)
Suggestの停止
clearTimeoutを実行して、
// --- suggest停止 ---
stop_suggest: function() {
clearTimeout(this.tid);
},
Suggest処理
検索テキストボックスに入力された文字列でビデオを検索し、
// --- suggest処理 ---
do_suggest: function() {
// Suggestが表示されていたら非表示にする。
$("#suggest").hide();
// 検索キーワードの処理
var str = $("#keyword").val();
if (str == null || str.length == 0) return;
if (this.preinput == str) return;
this.preinput = str;
// ajax通信定義
$.ajax({
dataType: "jsonp",
data: {
"vq": str,
"max-results": 10, // 10件分を検索
"alt":"json-in-script"
},
cache: true,
url: "http://gdata.youtube.com/feeds/api/videos",
success: function (data) {
// 検索キーワードにマッチするデータがない
if (data.feed.entry == null) return;
var suggests = [];
$("#suggest").empty(); // Suggestをクリア
$.each(data.feed.entry, function(i, item){
// ビデオに設定されているキーワードがない
if (item.media$group.media$keywords == null) return true;
// キーワードを配列に変換
var keywords = item.media$group.media$keywords.$t.split(", ");
if (keywords.length == 0) return true;
// 各キーワードを判別
$.each(keywords, function(n, keyword){
if ((keyword != str) && // 検索キーワードと違う
(keyword.indexOf(str) == 0) && // 検索キーワードで始まる
($.inArray(keyword, suggests) == -1)) { // 既にSuggestに追加されていない
suggests.push(keyword);
$("#suggest").append($("<option/>").text(keyword));
}
});
});
// Suggestが0件
if (suggests.length == 0) return;
// Suggestを表示
$("#suggest")
.show()
[0].selectedIndex = -1;
}
});
}
前処理
まず、
// Suggestが表示されていたら非表示にする。
$("#suggest").hide();
次に、
var str = $("#keyword").val();
もし、
if (str == null || str.length == 0) return;
if (this.preinput == str) return;
最後に次回の検索文字列と比較するために、
this.preinput = str;
ajax通信定義
基本的な構造は前回までのビデオ検索のものと変わりません。
よって、
各ビデオのエントリをイテレーションし、
$.each(data.feed.entry, function(i, item){
・・・
});
ビデオに設定されているキーワードがない場合は、
// ビデオに設定されているキーワードがない
if (item.media$group.media$keywords == null) return true;
$.eachのコールバック関数がtrueを返すと、
キーワードはカンマ+スペース
// キーワードを配列に変換
var keywords = item.media$group.media$keywords.$t.split(", ");
if (keywords.length == 0) return true;
キーワードの配列からSuggest文字列を抜き出します。
今回、
$.each(keywords, function(n, keyword){
if ((keyword != str) && // 検索キーワードと違う
(keyword.indexOf(str) == 0) && // 検索キーワードで始まる
($.inArray(keyword, suggests) == -1)) { // 既にSuggestに追加されていない
suggests.push(keyword);
$("#suggest").append($("<option/>").text(keyword));
}
});
$.inArray(value, array)
は、array
から、value
を検索し、value
が配列に存在しない場合は、
そして、
最後に、
// Suggestが0件
if (suggests.length == 0) return;
// Suggestを表示
$("#suggest")
.show()
[0].selectedIndex = -1;
以上で全ての実装が終了しました。サンプルを実行して動作を確認してみてください。
まとめ
今回はSuggestを実装してみました。
第3回までの内容が理解できていれば、
この実装では、
次回は、