クイック スタート: アプリへの検索の追加 (HTML)
ほとんどのユーザーは、探しているものを見つけるために検索機能を利用します。たとえば、アプリでメディア ファイルを再生する場合、ユーザーは特定の曲やビデオを検索できることを期待します。アプリが料理アプリの場合は、特定のレシピや材料を検索できることを期待します。
事前に計画しておけば、アプリに検索を追加することは難しいことではありません。必要なものは次のとおりです。
- 検索対象のデータ ソース。ユーザーが検索する可能性がある項目のカタログまたはインベントリが必要です。このインベントリをできるだけわかりやすいものにすると、検索結果の精度も向上します。
- 検索クエリを入力するためのコントロール。Windows には、アプリで使うことのできる SearchBox コントロールが用意されています。SearchBox は、クエリを入力するための入力領域、検索を実行するための検索ボタン、検索クエリを処理するためのイベントを提供します。また、自動的にいくつかの検索候補も提供します。
- 検索結果を表示するためのページ。Microsoft Visual Studio には、検索クエリと表示結果を処理するために必要な多くのコードを作成する検索結果ページ テンプレートが用意されています。
このクイック スタートでは、これらの項目を使って、アプリに検索機能を追加する方法について説明します。
この機能の実際の使い方については「アプリの機能の概要」シリーズの次のトピックをご覧ください: Windows ストア アプリ UI の概要
必要条件
- JavaScript を使った基本的な Windows ストア アプリにコントロールを追加できることを前提としています。コントロールを追加する手順については、「クイック スタート: コントロールの追加とイベントの処理」と「クイック スタート: WinJS コントロールとスタイルの追加」をご覧ください。
- データ ソースとデータ バインディングの使い方について理解している必要があります。手順について詳しくは、「Visual Studio のテンプレート データをカスタマイズする方法」をご覧ください。
データをセットアップする
ユーザーが検索クエリを入力すると、アプリではユーザーが探している可能性のある項目を検索します。アプリが検索するデータにはいくつかの形式があります。これには、XML ファイル、JavaScript Object Notation (JSON) データ、データベース、Web サービス、ファイル システム内のファイルがあります。
このクイック スタートの例では、Microsoft Visual Studio で新しいプロジェクトを作るときに Visual Studio によって生成されるサンプル データを使います。
Visual Studio を使って新しいグリッド アプリ、ハブ アプリ、スプリット アプリを作ると、アプリの js フォルダーに data.js という名前のファイルが作られます。このファイルには静的データが含まれており、独自のデータに置き換えることができます。たとえば、アプリで単一の xhr 要求を行って RSS データまたは JSON データを取得する場合、独自のコードを data.js に追加したいことがあります。このファイルにコードを含めると、検索結果ページで使われているデータ モデルを変更せずに、自分のデータを簡単に使うことができます。
次に示すのは、サンプル データの例です。
function generateSampleData() {
// . . .
var sampleGroups = [
{ key: "group1", title: "Group Title: 1", // . . .
// . . .
];
var sampleItems = [
{ group: sampleGroups[0], title: "Item Title: 1", // . . .
// . . .
];
return sampleItems;
}
このデータをファイルからアクセスできるようにするには、以下のメンバーを公開する Data
名前空間を data.js
ファイルで定義します。
items
: データ項目を含む WinJS.Binding.List。これは、グループ化された List です。groups
: データ項目が属しているグループを含む WinJS.Binding.List。items.groups を呼び出すことによってグループを取得することもできます。- getItemReference: 指定された項目のグループ キーとタイトルを含むオブジェクトを取得します。
- getItemsFromGroup: 指定されたキーを持つグループに属する項目を含む FilteredListProjection を取得します。
- resolveGroupReference: 指定されたキーを持つグループを表すオブジェクトを取得します。
- resolveItemReference: このメソッドは、2 つの文字列 (グループ キーとタイトル) を格納する配列を受け取ります。このメソッドは、指定されたグループ キーとタイトルを持つ項目を取得します。
データを格納するためにこの名前空間やメンバーを使う必要はありませんが、これらを使うと検索結果ページ テンプレートを使いやすくなります。
テンプレートによって生成されたデータの操作について詳しくは、「Visual Studio のテンプレート データをカスタマイズする方法」をご覧ください。
検索結果ページを追加する
検索結果ページでは、検索クエリを処理し、結果を表示します。プロジェクトに検索結果ページを追加してみましょう。以下の手順は、プロジェクトがハブ、グリッド、スプリット テンプレートから作られたことを前提としています。
検索結果ページ項目を追加する
ソリューション エクスプローラーの pages プロジェクト フォルダーに、search という名前の新しいフォルダーを追加します。
search フォルダーのショートカット メニューを開き、[追加]、[新しい項目] の順にクリックします。
[新しい項目の追加] ダイアログ ボックスの中央のウィンドウで、[検索結果ページ] を選びます。この例では、[名前] ボックスに表示される既定の名前、searchResults.html を使います。
[追加] をクリックします。
Visual Studio で、新しい search フォルダーのプロジェクトに searchResults.html、searchResults.css、searchResults.js が追加されます。
SearchBox を追加する
検索結果ページに対しても作業をする必要がありますが、最初に、このアプリに SearchBox を追加しましょう。 SearchBox を追加すると、検索結果ページを実装したときに、検索結果ページのテストが容易になります。
SearchBox を使ってユーザーはクエリを入力できます。検索候補を表示することもできます。アプリに SearchBox を追加するには、次のマークアップを HTML ページに追加します。
<div class="searchBox"
data-win-control="WinJS.UI.SearchBox"
data-win-options="{placeholderText: 'Search'}">
</div>
また、onquerysubmitted イベントに登録する必要があります。その作業は、後の手順で行います。
検索ボックスはどこに配置すればよいでしょうか。アプリの各ページに検索ボックスを配置すると、ユーザーは必要なときにいつでも簡単に検索できます。領域の問題がある場合は、上部のアプリ バーに検索ボックスを配置できます。
ページに SearchBox コントロールを追加する
アプリのいずれかのページに、SearchBox を追加しましょう。以下の手順は、Page コントロールに基づく任意のページに適用できます。
通常、SearchBox を配置するのに最適な場所は、ページの右上隅です。Visual Studio テンプレート (ページ コントロール テンプレートなど) から作るほとんどのページには、ページ タイトルと戻るボタンを含む header 要素があります。
<header aria-label="Header content" role="banner"> <button data-win-control="WinJS.UI.BackButton"></button> <h1 class="titlearea win-type-ellipsis"> <span class="pagetitle"></span> </h1> </header>
<header aria-label="Header content" role="banner"> <button data-win-control="WinJS.UI.BackButton"></button> <h1 class="titlearea win-type-ellipsis"> <span class="pagetitle">Welcome to basicPage</span> </h1> <div class="searchBox" data-win-control="WinJS.UI.SearchBox" data-win-options="{placeholderText: 'Search'}"> </div> </header>
(推奨) ユーザーがキーボードを使って入力を開始するだけでアプリ内のコンテンツを検索できるようにする必要があります。
多くのユーザーは、キーボードを使って Windows 8 との対話式操作を行います。ユーザーが入力による検索を行うことは、キーボード操作の効率的な使用につながり、アプリの検索エクスペリエンスがスタート画面と一貫性のあるものになります。
ユーザーが入力したときに検索ボックスで入力内容を受け取るようにするには、SearchBox コントロールの focusOnKeyboardInput プロパティを true に設定します
<div class="searchBox" data-win-control="WinJS.UI.SearchBox" data-win-options="{placeholderText: 'Search', focusOnKeyboardInput: true }"> </div>
Visual Studio によって作られた default.css スタイル シートは、ヘッダー要素を -ms-grid レイアウトにします。SearchBox をページの右上隅に設定するには、単にページのカスケード スタイル シート (CSS) ファイルにこのスタイルを追加します。
.searchBox { -ms-grid-column: 4; margin-top: 57px; margin-right: 29px; }
onquerysubmitted イベントを処理する
多くの場合、アプリには複数の SearchBox コントロールがあります。それらすべてが利用できる単一の onquerysubmitted イベント ハンドラーを定義しましょう。
アプリの default.js ファイルを開きます。
"querySubmittedHandler" という名前の onquerysubmitted イベント ハンドラーを作ります。このハンドラーは、"args" という名前の引数を 1 つだけ受け取ります。このメソッド定義は、既にある default.js コードをラップする匿名関数内のどこにでも記述できます。
function querySubmittedHandler(args) { }
このイベント ハンドラーを使って、WinJS.Navigation.navigate を呼び出して、新しい検索結果ページに移動します。
args.details
プロパティには、イベントに関する情報を提供するオブジェクトが含まれています。この情報を検索結果ページが必要とするため、WinJS.Navigation.navigate を呼び出すときは、このオブジェクトを渡します。function querySubmittedHandler(args) { WinJS.Navigation.navigate('/pages/search/searchResults.html', args.detail); }
警告 新しいアプリ テンプレートを使ってアプリを作った場合は、検索が機能するように、アプリにナビゲーション サポートを追加する必要があります。 ナビゲーションは、グリッド、スプリット、ナビゲーション アプリ テンプレートでの場合と同じ方法でサポートできます。
PageControlNavigator
というカスタム コントロールをアプリに追加してください。このカスタム コントロールでのナビゲーションのサポート方法については、「クイック スタート: 単一ページ ナビゲーションの使用」をご覧ください。カスタム コントロールを使わずにナビゲーションをサポートする場合は、WinJS.Navigation.navigated などのナビゲーション イベントをリッスンして応答する独自のコードを記述する必要があります。PageControlNavigator
などのカスタム コントロールを使わずにナビゲーションをサポートする方法の例については、ナビゲーションとナビゲーション履歴のサンプルをご覧ください。次に、名前空間を定義し、ハンドラーをメンバーにすることによって、このイベント ハンドラーを公開する必要があります。名前空間に "SearchUtils" という名前を付けます。また、イベント ハンドラーを宣言で設定できるように、WinJS.UI.eventHandler メソッドを使う必要もあります (このしくみについて詳しくは、「宣言を使ってイベント ハンドラーを設定する方法」をご覧ください)。
WinJS.Namespace.define("SearchUtils", { querySubmittedHandler: WinJS.UI.eventHandler(querySubmittedHandler) } );
SearchBox が含まれている HTML ページを開きます。data-win-options プロパティを使って、onquerysubmitted イベントを
SampleUtils.querySubmittedHandler
に設定します。<div class="searchBox" data-win-control="WinJS.UI.SearchBox" data-win-options="{placeholderText: 'Search', focusOnKeyboardInput: true, onquerysubmitted: SearchUtils.querySubmittedHandler}"> </div>
試してみましょう。アプリを実行し、SearchBox にテスト クエリを入力して Enter キーを押します。Visual Studio によって用意されたサンプル データを使っている場合は、テスト クエリとして "1" を使ってみます。
先ほど作った onquerysubmitted イベント ハンドラーに、入力したクエリが渡され、検索結果ページが表示されます。
サンプル データを使った場合は、テスト クエリと一致したものが表示されるはずです。独自のデータを使っている場合は、まだ結果を取得できない可能性があります。先に、検索結果ページを更新する必要があります。これについては、後の手順で説明します。
データを検索する
検索結果ページに戻りましょう。 アプリが検索結果ページに移動するときに、最初に呼び出されるメソッドの 1 つが、_handleQuery
メソッドです。 _handleQuery
は次のようなメソッドを呼び出しますが、それらは修正する必要があります。
_generateFilters
フィルターの一覧を生成します。ユーザーはこれをクリックして、結果をフィルター処理できます。
_searchData
データ内の一致する項目を検索し、
originalResults
という名前の List に保存します。_populateFilterBar
フィルター一覧内のフィルターを表示します。
これらのメソッドを更新して、独自のデータ用にカスタマイズしましょう。
フィルターを変更する
_generateFilters
メソッドは、フィルターの一覧を生成します。ユーザーはこれをクリックして、結果をフィルター処理できます。テンプレートによって生成されたメソッドは、3 つのフィルターを作ります。すべての結果を表示する "All" フィルターと、グループ 1 の項目を表示するフィルターと、他のすべてを表示するフィルターです。テンプレートによって生成されたコードを、フィルター一覧を動的に生成するコードに置き換えましょう。そのようにすれば、サンプル データを変更した場合、新しいフィルターがページに表示されます。ここでは _generateFilters
コードを更新し、2 つのヘルパー メソッドを作ります。しかし、その前に、グループの一覧にアクセスできるように data.js ファイルを更新する必要があります。これらのグループを使って、フィルターを定義します。
_generateFilters メソッドを更新する
searchResults.js で
_generateFilters
メソッドを探し、含まれているコードを削除します。_filters
配列を初期化します。_filters
配列は、検索結果ページによって定義されたメンバー変数です。_generateFilters: function () { this._filters = [];
ここで、フィルターを作ります。フィルターは、次の 3 つのプロパティを持つオブジェクトです。
results
: 表示する項目の List。ここでは、null に設定します。text
: フィルターのために表示するテキスト。predicate
: 項目を受け取る関数。項目がフィルター条件を満たす場合 (このフィルターが選ばれたときに表示されるべき項目である場合)、この関数は true を返します。それ以外の場合は false を返します。
まず、"All" フィルターを作りましょう。All フィルターは常に項目を表示するため、
predicate
は常に true を返します。this._filters.push({ results: null, text: "All", predicate: function (item) { return true; } });
次に、データ内の各グループのためのフィルターを作りましょう。グループは、
Data.groups
という名前の List として格納されます。List 内の各グループを反復処理するには、forEach メソッドを使います。forEach メソッドは、パラメーターとして関数を受け取ります。この関数は、一覧の各項目に対して呼び出されます。_createFiltersForGroups
という名前のメンバー関数を渡しましょう。この関数は、次の手順で作ります。if (window.Data) { Data.groups.forEach(this._createFiltersForGroups.bind(this)); } },
ここで、
_createFiltersForGroups
関数を作ります。element、index、array という 3 つのパラメーターを受け取る
_createFiltersForGroups
という名前のメンバー関数を作ります。_createFiltersForGroups: function (element, index, array){
element パラメーターには、グループ オブジェクトが含まれています。 新しいフィルター オブジェクトを作り、push メソッドを使ってそのオブジェクトを
_filters
配列に追加します。フィルターのresults
プロパティを null に、text
プロパティを element.title
に、predicate
プロパティを_filterPredicate
という名前の関数に設定します。_filterPredicate
メソッドは、次の手順で定義します。this._filters.push( { results: null, text: element.title, predicate: this._filterPredicate.bind(element)} ); },
item という名前の 1 つのパラメーターを受け取る
_filterPredicate
という名前のメンバー関数を作ります。item パラメーターのgroup
プロパティが現在のグループ オブジェクトと等しい場合は、true を返します。_filterPredicate: function (item) { return item.group === this; },
作ったばかりの 3 つのメソッドの完全なコードを次に示します。
_generateFilters: function () {
this._filters = [];
this._filters.push({ results: null, text: "All", predicate: function (item) { return true; } });
if (window.Data) {
Data.groups.forEach(this._createFiltersForGroups.bind(this));
}
},
_createFiltersForGroups: function (element, index, array){
this._filters.push(
{ results: null, text: element.title, predicate: this._filterPredicate.bind(element)}
);
},
_filterPredicate: function (item) {
return item.group === this;
},
アプリを実行し、検索を行います。新しいフィルターがフィルター バーに表示されます。
テンプレートによって生成されたサンプル データを使っている場合は、一部のグループがクリッピングされることがあります。この問題を修正するには、検索結果ページの CSS ファイルでいくつかの調整を行います。
検索結果ページの CSS を更新する
searchResults.css を開きます。
.searchResults section[role=main]
スタイルを探し、-ms-grid-rows プロパティの値を "auto 1fr" に変更します。.searchResults section[role=main] { /* Define a grid with rows for the filters and results */ -ms-grid-columns: 1fr; -ms-grid-rows: auto 1fr; -ms-grid-row: 1; -ms-grid-row-span: 2; display: -ms-grid; }
.searchResults section[role=main] .filterbar
スタイルを探して word-wrap プロパティの値を "normal" に変更し、margin-bottom を "20px" に設定します。.searchResults section[role=main] .filterbar { -ms-font-feature-settings: "case" 1; -ms-grid-row: 1; list-style-type: none; margin-left: 60px; margin-right: 60px; margin-top: 133px; max-width: calc(100% - 120px); position: relative; white-space: normal; z-index: 1; margin-bottom: 20px; }
.searchResults section[role=main] .filterbar li
スタイルを探し、display プロパティの値を "inline-block" に変更します。.searchResults section[role=main] .filterbar li { display: inline-block; margin-left: 20px; margin-right: 20px; margin-top: 5px; opacity: 0.6; }
.searchResults section[role=main] .resultslist
スタイルを探し、-ms-grid-row プロパティの値を "2" に変更して、-ms-grid-row-span を "1" に設定します。.searchResults section[role=main] .resultslist { -ms-grid-row: 2; -ms-grid-row-span: 1; height: 100%; position: relative; width: 100%; z-index: 0; }
アプリを実行し、他の検索を行います。今度はフィルターがすべて表示されます。
検索アルゴリズムを更新する
_searchData
メソッドは、検索クエリに一致する項目をデータで検索します。テンプレートによって生成されたコードは、各項目のタイトル、サブタイトル、説明を検索します。関連性に基づいて結果をランク付けする独自の検索コードを記述しましょう。
_searchData メソッドを更新する
searchResults.js を開き、
_searchData
メソッドを探して、含まれているコードを削除します。originalResults
という名前の変数を作ります。これが戻り値になります。// This function populates a WinJS.Binding.List with search results for the // provided query. _searchData: function (queryText) { // Create a variable for the results list. var originalResults;
クエリ テキストと、検索対象のテキストの両方を小文字に変換することによって、検索で大文字と小文字が区別されないようにしましょう。まずはクエリを小文字に変換して、
lowercaseQueryText
という名前の変数に保存します。// Convert the query to lowercase. var lowercaseQueryText = queryText.toLocaleLowerCase();
データにアクセスしようとする前に、データが存在していることを確かめましょう。
if (window.Data) {
data.js で用意されたサンプル データを使っている場合、項目は
Data.items
(WinJS.Binding.List オブジェクト) に格納されます。検索クエリに一致しない項目をフィルターで除外するには、createFiltered メソッドを使います。createFiltered メソッドは、フィルター処理関数をパラメーターとして受け取ります。このフィルター処理関数は、item というパラメーターを 1 つだけ受け取ります。List は一覧の各項目に対してこの関数を呼び出して、フィルター処理された一覧にその項目を含めるかどうかを判断します。 関数は、項目を含める場合は true を返し、項目を除外する場合は false を返します。
originalResults = Data.items.createFiltered( function (item) {
JavaScript では、既にあるオブジェクトに新しいプロパティをアタッチできます。
ranking
プロパティを item に追加し、値を "-1" に設定します。// A ranking < 0 means that a match wasn't found. item.ranking = -1;
まず、項目のタイトルにクエリ テキストが含まれているかどうかを確認します。含まれている場合は、項目に 10 点を与えます。
if (item.title.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) { item.ranking += 10; }
次に、サブタイトル フィールドでのヒットを確認します。一致が見つかった場合は、項目に 5 点を与えます。
if (item.subtitle.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) { item.ranking += 5; }
最後に、説明フィールドを確認します。一致が見つかった場合は、項目に 1 点を与えます。
if (item.description.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) { item.ranking += 1; }
項目のランキングが -1 である場合は、検索クエリに一致しなかったことを意味します。戻り値は、項目のランキングが 0 以上である場合、true を返します。
return (item.ranking >= 0); } );
ここまでで、検索クエリに一致する項目だけが一覧に含まれるようにフィルター処理し、ランキング情報を追加しました。次に、createSorted メソッドを使って、点が多い項目が最初に表示されるように結果一覧を並べ替えます。
// Sort the results by the ranking info we added. originalResults = originalResults.createSorted(function (firstItem, secondItem){ if (firstItem.ranking == secondItem.ranking) { return 0; } else if (firstItem.ranking < secondItem.ranking) return 1; else return -1; }); }
データが見つからない場合は、空の一覧を作ります。
else { // For some reason, the Data namespace is null, so we // create an empty list to return. originalResults = new WinJS.Binding.List(); }
最後に、結果を返します。
return originalResults; }
更新された _searchData
メソッドの完全なコードを次に示します。
_searchData: function (queryText) {
// Create a variable for the results list.
var originalResults;
// Convert the query to lowercase.
var lowercaseQueryText = queryText.toLocaleLowerCase();
if (window.Data)
{
originalResults = Data.items.createFiltered(
function (item) {
// A ranking < 0 means that a match wasn't found.
item.ranking = -1;
if (item.title.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
item.ranking += 10;
}
if (item.subtitle.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
item.ranking += 5;
}
if (item.description.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
item.ranking += 1;
}
return (item.ranking >= 0);
}
);
// Sort the results by the ranking info we added.
originalResults = originalResults.createSorted(function (firstItem, secondItem){
if (firstItem.ranking == secondItem.ranking) {
return 0;
}
else if (firstItem.ranking < secondItem.ranking)
return 1;
else
return -1;
});
}
else {
// For some reason, the Data namespace is null, so we
// create an empty list to return.
originalResults = new WinJS.Binding.List();
}
return originalResults;
}
検索によって返された項目へのナビゲーションを実装する
アプリを実行して検索を行うと、検索結果ページが ListView コントロールに結果を表示します。 この時点では、検索結果の項目のいずれかをクリックしても、何も起こりません。ユーザーがクリックしたときに項目が表示されるようにするためのコードを追加しましょう。
ListView 内の項目をユーザーがクリックすると、ListView で oniteminvoked イベントが発生します。検索結果ページ用の、テンプレートによって生成されたコードでは、_itemInvoked
という名前の oniteminvoked イベント ハンドラーが定義されています。呼び出された項目に移動するように、このコードを更新しましょう。
項目へのナビゲーションを追加するには
searchResults.js を開き、
_itemInvoked
関数に、適切なページに移動するためのコードを追加します。注意 ここに示された URI はハブ テンプレートに対応するものです。グリッド テンプレートの場合、URI は /pages/itemDetail/itemDetail.html となります。スプリット テンプレートの場合、URI は /pages/items/items.html となります。_itemInvoked: function (args) { args.detail.itemPromise.done(function itemInvoked(item) { // TODO: Navigate to the item that was invoked. var itemData = [item.groupKey, item.data.title]; WinJS.Navigation.navigate("/pages/item/item.html", { item: itemData }); }); },
(省略可能) ListView コントロールの itemTemplate を更新する
テンプレートで生成された検索結果ページには、Visual Studio によって作られたサンプル データ ソースを使うように設計されている itemTemplate が定義されています。各データ項目に、"image"、"title"、"subtitle"、"description" の各フィールドがあることを前提としています。
データ項目に他のフィールドがある場合は、itemTemplate を変更する必要があります。手順については、「クイック スタート: ListView の追加」をご覧ください。
(省略可能) 検索候補を追加する
検索候補は、検索ウィンドウにある検索ボックスの下に表示されます。候補によってユーザーの時間を節約でき、ユーザーがアプリで検索できるものについて貴重なヒントを提供できるため、候補は重要です。
候補は、複数のソースから取得できます。
- 候補を自分で定義できます。たとえば、自動車メーカーの一覧を作成することができます。
- アプリがローカル ファイルを検索する場合は、Windows から候補を取得できます。
- Web サービスや Web サーバーから候補を取得できます。
検索候補を表示する場合のユーザー エクスペリエンス ガイドラインについては、「検索のガイドラインとチェック リスト」をご覧ください。
ローカル ファイルに基づいて Windows から候補を追加するには、LocalContentSuggestionSettings を使います。この場合はコード行をいくつか追加するだけです。また、検索ボックス コントロールの onsuggestionsrequested イベントに登録して、他のソース (ローカルに定義されたリストや Web サービスなど) から取得した候補で構成される独自の候補リストを作ることもできます。このクイック スタートでは、onsuggestionsrequested イベントを処理する方法を示します。
検索候補を追加する方法を示した他のコード例については、SearchBox コントロールのサンプルをダウンロードしてください。このサンプルでは、使用可能な 3 種類のソースをすべて使って検索候補を追加する方法、および入力方式エディター (IME) によって生成されたクエリ テキストの代替形式を使って東アジア言語の候補を追加する方法について説明しています (アプリが日本語または中国語のユーザーによって使用される場合は、代替クエリ テキストを使うことをお勧めします)。
SuggestionsRequested イベントを処理する
アプリに複数の SearchBox コントロールがある可能性があります。default.js ファイルで、すべてのコントロールで使うことができる 1 つのイベント ハンドラーを定義しましょう。前の手順で作った
querySubmittedHandler
メソッドの後に、このコードを追加します。function suggestionsRequestedHandler(args) {
SearchBox クエリ テキストを小文字に変換します。
var query = args.detail.queryText.toLocaleLowerCase();
システムでは、ユーザーが以前に実行した検索などの検索候補が自動的に提供されます。システムが提供する検索候補に、指定した検索候補を追加しましょう。
// Retrieve the system-supplied suggestions. var suggestionCollection = args.detail.searchSuggestionCollection;
クエリに少なくとも 1 文字以上が含まれていることと、データにアクセスできることを確認します。
if (query.length > 0 && window.Data) {
データ内の各項目を反復処理し、一致する項目を確認します。一致する項目が見つかった場合は、検索候補のコレクションに一致する項目のタイトルを追加します。
Data.items.forEach( function (element, index, array) { if (element.title.substr(0, query.length).toLocaleLowerCase() === query) { suggestionCollection.appendQuerySuggestion(element.title); } });
args.detail.linguisticDetails.queryTextAlternatives
プロパティは、IME でテキストを入力するユーザーに対して、追加の候補を提供します。これらの候補を使うことによって、東アジア言語のユーザーの検索エクスペリエンスが向上します。元のクエリが含まれる文字列の代替クエリ テキストを確認し、検索候補の一覧に追加します。args.detail.linguisticDetails.queryTextAlternatives.forEach( function (element, index, array) { if (element.substr(0, query.length).toLocaleLowerCase() === query) { suggestionCollection.appendQuerySuggestion(element); } }); } }
検索候補のイベント ハンドラーに必要なコードはこれだけです。完成した
suggestionsRequestedHandler
メソッドは次のようになります。function suggestionsRequestedHandler(args) { var query = args.detail.queryText.toLocaleLowerCase(); // Retrieve the system-supplied suggestions. var suggestionCollection = args.detail.searchSuggestionCollection; if (query.length > 0 && window.Data) { Data.items.forEach( function (element, index, array) { if (element.title.substr(0, query.length).toLocaleLowerCase() === query) { suggestionCollection.appendQuerySuggestion(element.title); } }); args.detail.linguisticDetails.queryTextAlternatives.forEach( function (element, index, array) { if (element.substr(0, query.length).toLocaleLowerCase() === query) { suggestionCollection.appendQuerySuggestion(element); } }); } }
注 データ ソースが非同期の場合は、検索候補のコレクションへの更新を Promise でラップする必要があります。サンプル コードは List を使っています。これは同期データ ソースですが、List が非同期データ ソースである場合、メソッドは次のようになります。
function suggestionsRequestedHandler(args) { var query = args.detail.queryText.toLocaleLowerCase(); // Retrieve the system-supplied suggestions. var suggestionCollection = args.detail.searchSuggestionCollection; if (query.length > 0 && window.Data) { args.detail.setPromise(WinJS.Promise.then(null, function () { Data.items.forEach( function (element, index, array) { if (element.title.substr(0, query.length).toLocaleLowerCase() === query) { suggestionCollection.appendQuerySuggestion(element.title); } }); args.detail.linguisticDetails.queryTextAlternatives.forEach( function (element, index, array) { if (element.substr(0, query.length).toLocaleLowerCase() === query) { suggestionCollection.appendQuerySuggestion(element); } }); }) ); } }
検索候補のイベント ハンドラーに必要なコードはこれだけです。前の手順で定義した
SearchUtils
名前空間を通じて公開して、パブリックにアクセスできるようにしましょう。WinJS.Namespace.define("SearchUtils", { querySubmittedHandler: WinJS.UI.eventHandler(querySubmittedHandler), suggestionsRequestedHandler: WinJS.UI.eventHandler(suggestionsRequestedHandler) } );
次に、イベントを SearchBox に登録します。SearchBox が含まれている HTML ページを開き、onsuggestionsrequested イベントを
SearchUtils.suggestionsRequestedHandler
に設定します。<div class="searchBox" data-win-control="WinJS.UI.SearchBox" data-win-options="{placeholderText: 'Search', focusOnKeyboardInput: true, onquerysubmitted: SearchUtils.querySubmittedHandler, onsuggestionsrequested: SearchUtils.suggestionsRequestedHandler}"> </div>
検索コントラクトの実装 (以前のバージョンの Windows の場合)
Windows 8.1 より前には、アプリは検索チャームを使ってアプリ内検索を提供していました。開発者は、検索コントラクトを実装し、SearchPane API を使って、クエリを処理し、検索候補や結果を取得していました。
Windows 8 の検索コントラクトと SearchPane API のサポートは継続されますが、Windows 8.1 以降は、SearchPane の代わりに SearchBox コントロールを使うことをお勧めします。 SearchBox を使うアプリは、検索コントラクトを実装する必要はありません。
アプリで SearchPane と検索コントラクトを使う必要があるでしょうか。ユーザーがアプリを検索する頻度が低いと予想される場合は、SearchPane と検索コントラクトを使うことができます。検索ウィンドウをアクティブにするためにユーザーがクリックできる、検索グリフ (Segoe UI Symbol 0xE0094、15pt) のボタンをアプリで使うことをお勧めします。SearchPane と検索コントラクトを実装するコードを確認するには、検索コントラクトのサンプルをご覧ください。
要約と次のステップ
SearchBox コントロールと検索結果ページを使って、アプリに検索を追加しました。
ユーザーのための優れた検索エクスペリエンスの設計と作成に役立つガイドラインについては、「検索のガイドラインとチェック リスト」をご覧ください。