快速入门:向应用添加搜索 (HTML)

[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]

大部分用户依靠搜索查找他们所需的内容。例如,如果你的应用可以播放媒体文件,用户将期待他们可以搜索特定歌曲或视频;如果你的应用是一个烹饪应用,用户会期待搜索特定食谱或食材。

通过少量规划,将搜索添加到应用的过程并不难。需要的内容如下:

  • 用于搜索的数据源。你需要某种项目目录或清单,用户可能会在其中进行搜索。你的清单分类越详细,你的搜索结果就越理想。
  • 用于输入搜索查询的一种控件。Windows 提供 SearchBox 控件,你的应用可以使用它。SearchBox 提供用于输入查询的输入区域、用于执行搜索的搜索按钮,以及用于处理搜索查询的事件。它甚至还自动提供一些搜索建议。
  • 用于显示搜索结果的页面。Microsoft Visual Studio 提供“搜索结果页面”模板,它创建了许多处理搜索查询和展示结果所需的代码。

本快速入门将告诉你如何使用这些项目,以便向你的应用添加搜索功能。

请将此操作功能视为我们的应用功能大全系列的一部分。: Windows 应用商店应用 UI 全解

先决条件

设置你的数据

当用户输入搜索查询时,你的应用会搜索用户可能要查找的项目。你的应用搜索的数据可能采用以下几种形式:它可能是 XML 文件、JavaScript Object Notation (JSON) 数据、数据库、Web 服务,或者文件系统中的文件。

快速入门中的示例使用你在 Visual Studio 中创建新项目时 Microsoft 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.js 文件定义显示这些成员的 Data 命名空间:

  • items:包含数据项的 WinJS.Binding.List。这是已分组的 List
  • groups:包含数据项所属的组的 WinJS.Binding.List。(你还可以通过调用 items.groups 获取这些组。)
  • getItemReference:可检索包含组密钥和指定项的标题的对象。
  • getItemsFromGroup:可检索 FilteredListProjection,它包含属于带有指定密钥的组的项目。
  • resolveGroupReference:可检索表示带有指定密钥的组的对象。
  • resolveItemReference:此方法采用包含两个字符串、一个组密钥和标题的数组。此方法可检索具有指定组密钥和标题的项目。

你无需使用此命名空间或这些成员包含你的数据,但执行此操作将使使用“搜索结果页面”模板更简单。

(有关使用模板生成的数据的详细信息,请参阅如何自定义 Visual Studio 模板数据。)

添加搜索结果页面

“搜索结果页面”****可处理搜索查询并显示结果。让我们向项目添加一个此类页面。(这些说明假设你的项目从“中心”、“网格”或“拆分”模板创建。)

Hh465238.wedge(zh-cn,WIN.10).gif添加搜索结果页面项

  1. 在“解决方案资源管理器”的“页面”****项目文件夹中,添加一个名为 search 的新文件夹。

  2. 打开“search”文件夹的快捷菜单,然后选择“添加”****>“新建项目”。

  3. 在“添加新项”****对话框的中心窗格中,选择“搜索结果页面”。对于此示例,保留默认名称 searchResults.html,该名称会出现在“名称”****框中。

  4. 选择“添加”。

    Visual Studio 在新的 search 文件夹中向项目添加 searchResults.html、searchResults.css 和 searchResults.js。

我们仍需要在搜索结果页面上做一些工作,但首先让我们将 SearchBox 添加到应用中。 拥有 SearchBox 可使我们更轻松地在实现搜索结果页面时进行测试。

SearchBox 使用户能够输入查询。它也可以显示建议。若要向你的应用添加 SearchBox,仅需将此标记添加到 HTML 页面:

<div class="searchBox"
    data-win-control="WinJS.UI.SearchBox"
    data-win-options="{placeholderText: 'Search'}">
</div>

(你还需要为 onquerysubmitted 事件注册,我们将在稍后的步骤中执行此操作。)

应该将搜索框置于何处?我们建议在应用的每页上都放置搜索框,以便用户可以在需要时轻松地搜索。如果空间不足,你可以将搜索框放置在顶部应用栏中。

Hh465238.wedge(zh-cn,WIN.10).gif向页面添加 SearchBox

  1. 让我们向应用的其中一个页面添加 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>
    

    只需在 h1 元素后添加你的 SearchBox

            <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>
    
  2. (建议)你应该让用户只需使用键盘开始键入即可搜索应用中的内容。

    许多人都会使用键盘与 Windows 8 交互。让用户通过键入内容进行搜索可以有效使用键盘交互,并使你的应用的搜索体验与“开始”屏幕一致。

    SearchBox 控件的 focusOnKeyboardInput 属性设置为 true,以便搜索框在用户键入时接收输入。

                <div class="searchBox"
                     data-win-control="WinJS.UI.SearchBox"
                     data-win-options="{placeholderText: 'Search',
                     focusOnKeyboardInput: true }">
                </div>
    
  3. Visual Studio 为你创建的 default.css 样式表为标头元素提供 -ms-grid 布局。要在页面的右上角放置你的 SearchBox,只需将此样式添加到页面的级联样式表 (CSS) 文件:

    .searchBox {
        -ms-grid-column: 4;
        margin-top: 57px;
        margin-right: 29px;
    }
    

Hh465238.wedge(zh-cn,WIN.10).gif处理 onquerysubmitted 事件

  1. 你的应用将可能拥有多个 SearchBox 控件。让我们定义他们全都可以使用的单个 onquerysubmitted 事件处理程序。

    打开应用的 default.js 文件。

  2. 创建名为 "querySubmittedHandler" 的 onquerysubmitted 事件处理程序,此处理程序采用名为 "args" 单个参数。(你可以将此方法定义放于包装现有 default.js 代码的匿名函数内的任何位置。)

        function querySubmittedHandler(args) {
    
        }
    
  3. 通过调用 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)支持导航的示例。

     

  4. 现在我们需要通过定义一个命名空间并使该处理程序成为成员来公开显示此事件处理程序。我们来调用命名空间 "SearchUtils"。我们需要使用 WinJS.UI.eventHandler 方法,以便可以通过声明方式设置事件处理程序(有关此工作原理的详细信息,请参阅如何通过声明方式设置事件处理程序)。

        WinJS.Namespace.define("SearchUtils",
        {
            querySubmittedHandler: WinJS.UI.eventHandler(querySubmittedHandler)
        }
        );
    
  5. 打开包含你的 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 事件处理程序将导航至搜索结果页面,并传递你输入的查询。

测试查询的结果

如果已使用示例数据,你应当看到测试查询的匹配。如果使用你自己的数据,你可能尚未得到任何结果;我们将先需要更新搜索结果页面。我们将在稍后的步骤中涉及到这一点。

搜索你的数据

现在让我们回到搜索结果页面。 当应用导航到搜索结果页面时,它首先调用的其中一个方法是 _handleQuery 方法。 _handleQuery 调用多个我们应当修改的方法:

  1. _generateFilters

    生成用户可单击以筛选结果的筛选器列表。

  2. _searchData

    搜索你的数据,用于匹配项目并将它们存储在名为 originalResultsList 中。

  3. _populateFilterBar

    在我们的筛选器列表中显示筛选器。

让我们更新这些方法以为你的数据自定义它们。

更新筛选器

_generateFilters 方法生成用户可单击以筛选结果的筛选器列表。模板生成的方法创建三种筛选器:用于显示所有结果的“所有”筛选器,用于显示组 1 中的项目的筛选器,以及用于显示所有其他内容的筛选器。让我们用动态生成的筛选器列表的代码替换模板生成的代码。这样,如果你更改示例数据,你的新筛选器将在页面上显示。我们将更新 _generateFilters 代码并创建两个帮助程序方法。但是首先,我们需要更新 data.js 文件以便我们可以访问组列表;我们使用这些组定义我们的筛选器。

Hh465238.wedge(zh-cn,WIN.10).gif更新 _generateFilters 方法

  1. 在 searchResults.js 中,找到 _generateFilters 方法并删除其包含的代码。

  2. 初始化 _filters 数组。 (_filters 数组是由搜索结果页面定义的成员变量。)

    
            _generateFilters: function () {
                this._filters = [];
    
  3. 现在创建一个筛选器。筛选器是具有三个属性的对象:

    • results:要显示的项目的 List。我们暂时将它设置为 null
    • text:该筛选器的显示文本。
    • predicate:选取项目的函数。如果该项目符合筛选标准(如果在选中此筛选器时它应当显示),则此函数返回 true;否则,它返回 false

    首先,让我们创建“所有”筛选器。“所有”筛选器始终显示项目,因此它的 predicate 始终返回 true

    
                this._filters.push({ results: null, text: "All", predicate: function (item) { return true; } });
    
  4. 现在让我们为数据中的每个组创建筛选器。我们的组存储为名为 Data.groupsList。使用 forEach 方法循环访问 List 中的每个组。forEach 方法采取一个函数作为它的参数;将为列表中的每个项目调用此函数。让我们向其传递一个名为 _createFiltersForGroups 的成员函数;我们将在下一步中创建该函数。

                if (window.Data) {
                    Data.groups.forEach(this._createFiltersForGroups.bind(this));
                }
            },
    
  5. 现在,让我们来创建 _createFiltersForGroups 函数。

    1. 创建具有以下三个参数的名为 _createFiltersForGroups 的成员函数:elementindexarray

              _createFiltersForGroups: function (element, index, array){
      
      
    2. element 参数包含我们的组对象。 创建新的筛选器对象,并使用推送方法将其添加到 _filters 数组。将筛选器的 results 属性设置为 null、将其 text 属性设置为 element.title,并将其 predicate 属性设置为名为 _filterPredicate 的函数。在下一步,你将定义 _filterPredicate 方法。

                  this._filters.push(
                      { results: null, text: element.title, predicate: this._filterPredicate.bind(element)}
                      );
              },
      
    3. 创建具有以下单个参数的名为 _filterPredicate 的成员函数:item。如果 item 参数的 group 属性等于当前组对象,则返回 true

              _filterPredicate: function (item) {
      
                  return item.group === this;          
              },
      

下面是我们刚刚创建的三个方法的完整代码:

        _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 文件进行一些调整来解决此问题。

Hh465238.wedge(zh-cn,WIN.10).gif更新搜索结果页面的 CSS

  1. 打开 searchResults.css。

  2. 找到 .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;
    }
    
  3. 找到 .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; 
        }
    
  4. 找到 .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;
            }
    
  5. 找到 .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 方法搜索匹配搜索查询的项目的数据。模板生成的代码搜索标题、副标题和每个项目的描述。让我们编写我们自己的按相关度为结果分级的搜索代码。

Hh465238.wedge(zh-cn,WIN.10).gif更新 _searchData 方法

  1. 打开 searchResults.js,找到 _searchData 方法并删除其包含的代码。

  2. 创建名为 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;
    
  3. 让我们通过将我们查看的查询文本和我们正在查看的文本转换为小写,来使搜索不区分大小写。让我们从将查询转换为小写并将其存储为名为 lowercaseQueryText 的变量开始。

                // Convert the query to lowercase. 
                var lowercaseQueryText = queryText.toLocaleLowerCase();
    
  4. 在尝试访问数据前,让我们先确保该数据存在。

                if (window.Data)
                {
    
  5. 如果你在使用 data.js 中提供的示例数据,那么我们的项目存储在 Data.items(一个 WinJS.Binding.List 对象)中。使用 createFiltered 方法筛选掉不满足搜索查询的项目。

    createFiltered 方法采用筛选函数作为其参数。此筛选函数采用单个参数 itemList 对列表中的每个项目调用此函数以确定它是否应在已筛选列表中。 如果应当包括该项目,该函数返回 true,如果应当省略,则返回 false

                    originalResults = Data.items.createFiltered(
    
                        function (item) {
    
  6. 在 JavaScript 中,你可以向现有对象附加新属性。将 ranking 属性添加到 item 并将其值设置为 "-1"。

                            // A ranking < 0 means that a match wasn't found. 
                            item.ranking = -1;
    
  7. 首先,让我们检查项目的标题是否包含查询文本。如果它包含,则给该项目 10 个点。

                            if (item.title.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
    
                                item.ranking += 10;
                            }
    
  8. 接下来,让我们检查副标题字段中的命中情况。如果找到匹配,则给该项目 5 个点。

                            if (item.subtitle.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
                                item.ranking += 5;
                            }
    
  9. 最后,让我们检查描述字段。如果找到匹配,则给该项目 1 个点。

                            if (item.description.toLocaleLowerCase().indexOf(lowercaseQueryText) >= 0) {
                                item.ranking += 1;
                            }
    
  10. 如果项目的分级为 -1,则意味着它不匹配搜索查询。对于我们的返回值,如果该项目的分级为 0 或更大,则返回 true

                            return (item.ranking >= 0);
                        }
                     );
    
  11. 到目前为止,我们已将列表筛选为仅有匹配搜索查询和已添加分级信息的项目。现在让我们使用 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;
                        });
    
                }
    
  12. 如果丢失数据,则创建空白列表。

                else {
    
                    // For some reason, the Data namespace is null, so we 
                    // create an empty list to return. 
                    originalResults = new WinJS.Binding.List();
    
                }
    
  13. 最后,返回结果。

                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 事件。搜索结果页面的模板生成的代码定义名为 _itemInvokedoniteminvoked 事件处理程序。让我们更新该代码以导航到调用的项目。

Hh465238.wedge(zh-cn,WIN.10).gif将导航添加到项目的步骤

  • 打开 searchResults.js,并向 _itemInvoked 函数添加代码以导航到正确页面。小心  此处显示的 URI 适用于中心模板。关于网格模板,URI 必须为: /pages/itemDetail/itemDetail.html.关于拆分模板,URL 必须为: /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

模板生成搜索结果页面定义一个 itemTemplate,它设计为与 Visual Studio 为你创建的示例代码源一起使用;它预期每个数据项中存在以下字段:"图像"、"标题"、"子标题"和"说明"。

如果你的数据项具有不同字段,你需要修改 itemTemplate。有关说明,请参阅快速入门:添加 ListView

(可用)添加搜索建议

搜索建议显示在搜索窗格的搜索框下。建议非常重要,因为这样可以节省用户的时间,并且可以对用户可在应用中搜索的各种内容提供宝贵的提示。

你可以从多个来源获取建议:

  • 你可以自己定义建议。例如,你可以创建一个汽车制造商列表。
  • 如果你的应用搜索本地文件,你可以从 Windows 获取建议。
  • 你可以从 Web 服务或服务器获取建议。

有关显示建议的用户体验指南,请参阅搜索指南和清单

你可以基于 Windows 的本地文件使用 LocalContentSuggestionSettings 来添加建议,只需几行代码即可。此外,你可以注册搜索框控件的 onsuggestionsrequested 事件,并构建你自己的建议列表,这些建议由你从其他源(如本地定义的列表或 Web 服务)检索到的建议组成。本快速入门向你显示如何处理 onsuggestionsrequested 事件。

有关介绍如何添加搜索建议的其他代码示例,请下载 SearchBox 控件示例。该示例演示了如何通过使用所有三种可能的来源添加搜索建议,以及如何通过使用由输入法编辑器 (IME) 生成的查询文本的替代形式来添加东亚语言的建议。(如果你的应用将由日本或中国用户使用,我们建议使用查询文本替代形式。)

Hh465238.wedge(zh-cn,WIN.10).gif处理 SuggestionsRequested 事件

  1. 你的应用可能具有多个 SearchBox 控件;让我们在你的 default.js 文件中定义它们可以共用的单个事件处理程序。在之前步骤中创建的 querySubmittedHandler 方法之后添加此代码。

        function suggestionsRequestedHandler(args) {
    
  2. SearchBox 查询文本转换为小写。

            var query = args.detail.queryText.toLocaleLowerCase();
    
  3. 系统将自动提供一些搜索建议,例如用户之前执行的搜索。让我们将自己的搜索建议添加到系统提供的内容中。

            // Retrieve the system-supplied suggestions.
            var suggestionCollection = args.detail.searchSuggestionCollection;
    
  4. 验证该查询包含至少一个字符,并且我们有权限访问我们的数据。

            if (query.length > 0 && window.Data) {
    
  5. 循环访问数据中的每个项目并查找匹配项目。当我们找到匹配时,将匹配项目的标题附加到搜索建议集合中。

                Data.items.forEach(
                    function (element, index, array) {
                        if (element.title.substr(0, query.length).toLocaleLowerCase() === query) {
                            suggestionCollection.appendQuerySuggestion(element.title);
                        }
    
                    });
    
  6. 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);
                                }
    
                            });
    
                    })
                 );
            }
        }
    
  7. 这是我们的搜索建议事件处理程序所需的所有代码。让我们通过在之前的步骤中定义的 SearchUtils 命名空间中公开使其可公开访问:

        WinJS.Namespace.define("SearchUtils",
        {
            querySubmittedHandler: WinJS.UI.eventHandler(querySubmittedHandler),
            suggestionsRequestedHandler: WinJS.UI.eventHandler(suggestionsRequestedHandler)
        }
        );
    
  8. 现在,让我们使用 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,我们建议使用 SearchBox 控件代替 SearchPane。 使用 SearchBox 的应用不需要实现“搜索”合约。

应用是否应该使用 SearchPane 和“搜索”合约?如果你认为用户不会经常搜索你的应用,你可以使用 SearchPane 和“搜索”合约。我们建议你在应用中使用带有“搜索”字形(大小为 15pt 的 Segoe UI Symbol 0xE0094)的按钮,用户可以单击它以激活搜索窗格。若要查看用于实现 SearchPane 和“搜索”合约的代码,请参阅“搜索”合约示例

摘要和后续步骤

你使用了 SearchBox 控件和“搜索结果页面”将搜索添加到你的应用。

有关帮助你为用户设计和创造良好搜索体验的指南,请参阅搜索指南和清单

相关主题

SearchBox 控件示例

搜索指南和清单