部分 3:PageControl 对象和导航 (HTML)

Applies to Windows only

你在前面教程中创建的“Hello, world”""应用只包含一页内容。但大多数实际的应用都包含多个页面。

可在 Windows 应用商店应用中使用各种导航模式。导航模式将帮助你为应用选择最佳导航模式。

注意  

请参见正在使用的两种主要导航模式(平面导航分层导航),这是应用功能大全系列的一部分。

在本教程中,你将“Hello, world”""应用中的代码复制到使用 Navigation App 模板的新应用中,然后添加一个额外的页面。

了解操作方法:

  • 如何使用 Navigation App 项目模板创建包含多页内容的应用。
  • 如何使用 PageControl 对象将你的代码分隔成模块化的单元。
  • 如何使用单页导航模型在页面之间进行导航。
  • 如何使用 NavBar 提供导航命令。

提示  

如要跳过本教程直接进入代码部分,请参阅 JavaScript 入门:本系列教程的完整代码

开始之前...

关于 Windows 应用商店应用中的导航

几乎所有的网站都提供某种形式的导航(通常采用超链接形式),你可以通过单击超链接来转至其他页面。每个页面都包含其自己的 JavaScript 函数和数据集、要显示的新 HTML 集以及样式信息等等。这种导航模型被称为多页导航。 该设计适合大多数网站,但对于某个应用它可能会引发问题,因为在不同的页面之间保持状态很不容易。

另一种导航模型是单页导航,在这种模型中,你可以针对你的应用使用单一页面并根据需要在该页中加载额外的数据。你仍然可以将应用程序拆分为多个文件,但你的应用会将其他文档加载到主页,而不是在页面之间移动。由于你的应用的主页和脚本从来不卸载,因而更容易管理状态、过渡或动画。我们建议让 Windows 应用商店应用使用单页导航模型。

为了帮助你创建使用单页导航模型的应用,Windows JavaScript 库提供了 WinJS.UI.Pages.PageControl 对象。还有 Navigation App 项目模板,该模板提供某些额外的导航基础结构。 在下一步中,将使用该模板创建新的项目。

步骤 1:在 Visual Studio 中创建新的导航应用

让我们创建一个使用 Navigation App 模板且名为 HelloWorldWithPages 的新应用。以下是操作方法:

  1. 启动 Microsoft Visual Studio Express 2013 for Windows。
  2. 在“文件”菜单上,选择“新建项目”。

    会出现“新建项目”对话框。可以在对话框的左侧窗格中选择要显示模板的类型。

  3. 在左侧窗格中,依次展开“已安装”、“模板”JavaScript,然后选择“Windows 应用商店”模板类型。对话框的中心窗格会显示一列适用于 JavaScript 的项目模板。

    在本教程中,我们使用 Navigation App 模板。

  4. 在中心窗格中,选择 Navigation App 模板。
  5. Name 文本框中,输入 "HelloWorldWithPages"。
  6. 取消选中“创建解决方案的目录”复选框。

    “新建项目”窗口

  7. 单击“确定”以创建项目。

    Visual Studio 会创建项目并在“解决方案资源管理器”中显示该项目。

    HelloWorldWithPages 项目的解决方案资源管理器

注意到,你的新 Navigation App 包含的文件比“Hello, world”""应用包含的文件多。让我们来看一看这些新文件:

  • /pages/home/home.css、/pages/home/home.html 和 /pages/home/home.js

    这三种页面为应用的主页定义了 PageControlPageControl 由 HTML 文件、JavaScript 文件和 CSS 文件组成。PageControl 是 HTML、CSS 和 JavaScript 的一个模块化单元,可用于导航(如 HTML 页面)或用作自定义控件。你可以使用 PageControl 对象将大的应用分割为较小的、较容易管理的部分。

    PageControl 对象支持多种方法,因此,相比使用宽松 HTML、CSS 和 JavaScript 页面的集合,在应用中使用这些对象将更加简单。你将在后面的步骤中了解有关这些方法的更多内容。

  • /js/navigator.js

    此文件提供 PageControlNavigator 帮助程序类,你可以使用它来显示 PageControl 对象并在它们之间进行导航。你无需使用它来显示 PageControl,但是它可以让你更轻松地使用这些对象。

让我们看一下新应用的 default.html 页面:


<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>HelloWorldWithPages</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>

    <!-- HelloWorldWithPages references -->
    <link href="/css/default.css" rel="stylesheet" />
    <script src="/js/default.js"></script>
    <script src="/js/navigator.js"></script>
</head>
<body>

    <div id="contenthost" data-win-control="Application.PageControlNavigator" 
        data-win-options="{home: '/pages/home/home.html'}"></div>
    <!-- <div id="appbar" data-win-control="WinJS.UI.AppBar">
        <button data-win-control="WinJS.UI.AppBarCommand" 
            data-win-options="{id:'cmd', label:'Command', icon:'placeholder'}" 
            type="button"></button>
    </div> -->
</body>
</html>

文件的 body 包含两个元素:PageControlNavigatordiv 元素和 AppBar 的注释掉的 div。 让我们暂时忽略 app bar,仔细看看第一个 div 元素。



    <div id="contenthost" data-win-control="Application.PageControlNavigator" 
        data-win-options="{home: '/pages/home/home.html'}"></div>
 

这个 div 元素创建一个 PageControlNavigator 控件。 PageControlNavigator 为我们加载和显示主页。使用 data-win-options 属性来告诉它要加载哪个页面 (/pages/home/home.html)。

继续进行并运行应用。

HelloWorldWithPages 应用

尽管它不是很明显,但应用实际上显示了 default.html 和 home.html。这类似于使用 iframe 在另一个 HTML 页面中显示 HTML 页面。

home.html PageControl 从 default.html 页面中显示。

步骤 2:复制“Hello, world”应用中的 HTML 和 CSS 内容

新应用有两个 HTML 页面:default.html 和 home.html。将你的内容放置到哪里?

  • 对于英国使用存在的 UI 使用 default.html,无论应用显示哪个页面都是如此。例如,可以使用 default.html 来托管导航栏。

  • 对于组成应用中单个屏幕的内容,使用页面,如 home.html。

让我们打开 home.html 并看一看它包含的某些标记。

  • 它具有一个 head 元素,该元素包含对 WinJS 代码和样式表的引用。还包含对应用的默认样式表 (default.css) 的引用以及组成主页 (home.css 和 home.js)的其他文件的引用。

    
    
    <head>
        <meta charset="utf-8" />
        <title>homePage</title>
    
        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
        <script src="//Microsoft.WinJS.2.0/js/base.js"></script>
        <script src="//Microsoft.WinJS.2.0/js/ui.js"></script>
    
        <link href="/css/default.css" rel="stylesheet" />
        <link href="/pages/home/home.css" rel="stylesheet" />
        <script src="/pages/home/home.js"></script>
    </head>
    
    
    
  • 它具有一个页面标头区域,该区域包含用于向后导航的 BackButton 和一个标题区域。模板包含在向后导航时自动启用后退按钮的代码。在此处添加另一个页面和导航之前,该按钮不可见。

    
    
            <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 HelloWorldWithPages!</span>
                </h1>
            </header>
    
    
    
  • 它包含一个用于主要内容的部分。

    
    
            <section aria-label="Main content" role="main">
                <p>Content goes here.</p>
            </section>
    
    
    

让我们将“Hello, world”""应用中的内容添加到新的 HelloWorldWithPages 项目的主页 (home.html) 中。

JJ663505.wedge(zh-cn,WIN.10).gif添加“Hello, world”""应用中的 HTML 和 CSS 内容

  1. 将最终的 HTML 内容从 "Hello, world" 应用的 default.html 文件复制到新项目的 /pages/home/home.html 中的主要内容部分。
    
    <body>
        <!-- The content that will be loaded and displayed. -->
        <div class="fragment homepage">
            <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 HelloWorldWithPages!</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
    
                <!-- Copied from "Hello, world" -->
                <h1 class="headerClass">Hello, world!</h1>
                <div class="mainContent">
                    <p>What's your name?</p>
                    <input id="nameInput" type="text" />
                    <button id="helloButton">Say "Hello"</button>
                    <div id="greetingOutput"></div>
                    <label for="ratingControlDiv">
                        Rate this greeting: 
                    </label>
                    <div id="ratingControlDiv" data-win-control="WinJS.UI.Rating">
                    </div>
                    <div id="ratingOutput"></div>
                </div>
            </section>
        </div>
    </body>
    
    
  2. 将复制的标题内容移动到 home.html 为你提供的 h1 元素中。由于 home.html 已包含一个主要内容部分,因此删除你复制的 "mainContent" div 元素(但保留其内容)。
    
    <body>
        <!-- The content that will be loaded and displayed. -->
        <div class="fragment homepage">
            <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 HelloWorldWithPages!</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
     
                <p>What's your name?</p>
                <input id="nameInput" type="text" />
                <button id="helloButton">Say "Hello"</button>
                <div id="greetingOutput"></div>
                <label for="ratingControlDiv">
                    Rate this greeting: 
                </label>
                <div id="ratingControlDiv" data-win-control="WinJS.UI.Rating">
                </div>
                <div id="ratingOutput"></div>
            </section>
        </div>
    </body>
    
    
  3. 切换到浅色样式表。替换深色样式表的引用:
    
    
        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    
    
    

    使用此表:

    
    
        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.2.0/css/ui-light.css" rel="stylesheet" />
    
    
    
  4. 每个 PageControl 都拥有其自己的级联样式表 (CSS) 文件。

    greetingOutput 样式从你在第 1 部分:创建“Hello, world!”应用中创建的 default.css 文件复制到 home.css。

    
    .homepage section[role=main] {
        margin-left: 120px;
        margin-right: 120px;
    }
    
    #greetingOutput {
        height: 20px; 
        margin-bottom: 40px;
    }
    
    
  5. 运行应用。

    此时,HelloWorldWithPages 应用便具有“Hello, world”应用中的内容

    你已经重新创建了原始“Hello, world”""应用中的内容。接下来,我们通过复制“Hello, world”""事件处理程序来添加交互。

步骤 3:复制事件处理程序

每个 PageControl 都有自己的 JavaScript 文件。让我们来看一看 Visual Studio 为 "home" PageControl 创建的 JavaScript 文件,即 home.js:


(function () {
    "use strict";

    WinJS.UI.Pages.define("/pages/home/home.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
            // TODO: Initialize the page here.
        }
    });
})();

该文件看起来与你的 default.js 文件有很多不同。有一个内容,它更短。这是因为 default.js 已经处理激活和核心应用逻辑。每个 PageControl 只需要包含页面自身的逻辑。

其中代码的前几行,即对 WinJS.UI.Page.define 函数的调用会创建 PageControl 对象。该函数带有两个参数:页面的 URI(在该示例中为 "/pages/home/home.html")以及定义 PageControl 的成员的对象。你可以添加所需的任何类型的成员。还可以实现一组特定成员,如 IPageControlMembers 接口所述,这些成员在你使用 PageControl 时自动被应用调用。

模板创建的 home.js 文件定义这些特定成员之一,即 ready 函数。初始化并呈现你的页面之后调用 ready 函数。 这是附加事件处理程序的好地方。

你可能注意到代码并不包含对 WinJS.UI.processAll 的调用。这是因为 PageControl 会自动为你调用它。调用 ready 函数时,WinJS.UI.processAll 已经被调用并且已完成它的处理。

JJ663505.wedge(zh-cn,WIN.10).gif添加事件处理程序的步骤

  1. 第 1 部分:创建“Hello, world!”应用第 2 部分:管理应用生命周期和状态中,你定义了三个事件处理程序:buttonClickHandlerratingChangednameInputChanged。将这些事件处理程序复制到你的 home.js 文件并使它们成为你的 PageControl 的成员。将它们添加到模板为你创建的 ready 函数后面。

    
        WinJS.UI.Pages.define("/pages/home/home.html", {
    
            // This function is called whenever a user navigates to this page. It
            // populates the page elements with the app's data.
            ready: function (element, options) {
                // TODO: Initialize the page here.
    
            },
    
            buttonClickHandler: function (eventInfo) {
    
                var userName = document.getElementById("nameInput").value;
                var greetingString = "Hello, " + userName + "!";
                document.getElementById("greetingOutput").innerText = greetingString;
    
                // Save the session data. 
                WinJS.Application.sessionState.greetingOutput = greetingString;
            },
    
            ratingChanged: function (eventInfo) {
    
                var ratingOutput = document.getElementById("ratingOutput");
                ratingOutput.innerText = eventInfo.detail.tentativeRating;
    
                // Store the rating for multiple sessions.
                var appData = Windows.Storage.ApplicationData.current;
                var roamingSettings = appData.roamingSettings;
                roamingSettings.values["greetingRating"] = eventInfo.detail.tentativeRating;
            },
    
            nameInputChanged: function (eventInfo) {
                var nameInput = eventInfo.srcElement;
    
                // Store the user's name for multiple sessions.
                var appData = Windows.Storage.ApplicationData.current;
                var roamingSettings = appData.roamingSettings;
                roamingSettings.values["userName"] = nameInput.value;
            }
    
    
        });
    
    
  2. 现在,我们需要附加我们的事件处理程序。在第 1 和第 2 部分中,我们为 WinJS.UI.processAll 返回的 Promise 创建了一个 then 函数。 现在,事情变得更加简单,因为我们可以使用 ready 函数来附加我们的事件处理程序。在 PageControl 自动为我们调用 WinJS.UI.processAll 之后调用 ready 函数。

    将附加事件处理程序的代码复制到 home.js 中的 ready 函数中。

    
            // This function is called whenever a user navigates to this page. It
            // populates the page elements with the app's data.
            ready: function (element, options) {
                // TODO: Initialize the page here.
    
                // Retrieve the div that hosts the Rating control.
                var ratingControlDiv = document.getElementById("ratingControlDiv");
    
                // Retrieve the actual Rating control.
                var ratingControl = ratingControlDiv.winControl;
    
                // Register the event handler. 
                ratingControl.addEventListener("change", this.ratingChanged, false);
    
                // Retrieve the button and register our event handler. 
                var helloButton = document.getElementById("helloButton");
                helloButton.addEventListener("click", this.buttonClickHandler, false);
    
                // Retrieve the input element and register our
                // event handler.
                var nameInput = document.getElementById("nameInput");
                nameInput.addEventListener("change", this.nameInputChanged);
    
            },
    
    
  3. 运行应用。当你输入一个名称并单击该按钮时,它显示一个问候。当你评价该问候时,它显示评级数值。

    选择评级之后的 HelloWorldWithPages 应用

步骤 4:还原应用状态

我们几乎重新创建了我们在“Hello, world”""应用中拥有的功能。现在,我们唯一需要做的就是在用户启动应用时还原应用的状态。

你可能还记得,我们有两种类型的应用状态要还原:

  • 用户名和评级。无论关闭应用的方式如何,我们都会还原该状态。
  • 个性化问候。仅当应用成功终止上次运行时我们才还原该状态。

JJ663505.wedge(zh-cn,WIN.10).gif还原应用状态的步骤

  1. 复制“Hello, world”""应用中还原用户名和评级的代码。将该代码添加到 home.js 的 ready 函数中。
    
            // This function is called whenever a user navigates to this page. It
            // populates the page elements with the app's data.
            ready: function (element, options) {
                // TODO: Initialize the page here.
    
                // Retrieve the div that hosts the Rating control.
                var ratingControlDiv = document.getElementById("ratingControlDiv");
    
                // Retrieve the actual Rating control.
                var ratingControl = ratingControlDiv.winControl;
    
                // Register the event handler. 
                ratingControl.addEventListener("change", this.ratingChanged, false);
    
                // Retrieve the button and register our event handler. 
                var helloButton = document.getElementById("helloButton");
                helloButton.addEventListener("click", this.buttonClickHandler, false);
    
                // Retrieve the input element and register our
                // event handler.
                var nameInput = document.getElementById("nameInput");
                nameInput.addEventListener("change", this.nameInputChanged);
    
                // Restore app data. 
                var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
    
                // Restore the user name.
                var userName =
                    Windows.Storage.ApplicationData.current.roamingSettings.values["userName"];
                if (userName) {
                    nameInput.value = userName;
                }
    
                // Restore the rating. 
                var greetingRating = roamingSettings.values["greetingRating"];
                if (greetingRating) {
                    ratingControl.userRating = greetingRating;
                    var ratingOutput = document.getElementById("ratingOutput");
                    ratingOutput.innerText = greetingRating;
                }
    
            },
    
    
  2. 仅当应用成功终止上次运行时我们才还希望还原个性化问候。遗憾的是,PageControl 不提供检查应用之前的执行状态的内置方法:default.js 文件中向 onactivated 事件处理程序提供该信息。 但是此问题有一个简单的解决方案:只需在 sessionState 对象中保存应用之前的执行状态,以便 PageControl 可以访问它。
    1. 在 default.js 文件中,向 onactivated 处理程序添加代码以保存之前的执行状态。通过向名为 previousExecutionStatesessionState 对象添加属性来保存状态。
      
          app.addEventListener("activated", function (args) {
              if (args.detail.kind === activation.ActivationKind.launch) {
                  if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
                      // TODO: This application has been newly launched. Initialize
                      // your application here.
                  } else {
                      // TODO: This application has been reactivated from suspension.
                      // Restore application state here.
                  }
      
                  // Save the previous execution state. 
                  WinJS.Application.sessionState.previousExecutionState = 
                      args.detail.previousExecutionState;
      
                  if (app.sessionState.history) {
                      nav.history = app.sessionState.history;
                  }
                  args.setPromise(WinJS.UI.processAll().then(function () {
                      if (nav.location) {
                          nav.history.current.initialPlaceholder = true;
                          return nav.navigate(nav.location, nav.state);
                      } else {
                          return nav.navigate(Application.navigator.home);
                      }
                  }));
              }
          });
      
      
    2. 在 home.js 文件中,向检查 previousExecutionState 数据的 ready 方法添加代码。如果之前的执行状态是 terminated,请还原个性化问候(你可以从 "Hello, world" 应用中的 default.js 文件复制执行此操作的代码。)
      
                  // If the app was terminated last time it ran, restore the personalized
                  // greeting. 
                  if (
                      WinJS.Application.sessionState.previousExecutionState
                      === Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                      var outputValue = WinJS.Application.sessionState.greetingOutput;
                      if (outputValue) {
                          var greetingOutput = document.getElementById("greetingOutput");
                          greetingOutput.innerText = outputValue;
                      }
      
                  }
      
      

      以下是完整的 ready 方法。

      
              // This function is called whenever a user navigates to this page. It
              // populates the page elements with the app's data.
              ready: function (element, options) {
                  // TODO: Initialize the page here.
      
                  // Retrieve the div that hosts the Rating control.
                  var ratingControlDiv = document.getElementById("ratingControlDiv");
      
                  // Retrieve the actual Rating control.
                  var ratingControl = ratingControlDiv.winControl;
      
                  // Register the event handler. 
                  ratingControl.addEventListener("change", this.ratingChanged, false);
      
                  // Retrieve the button and register our event handler. 
                  var helloButton = document.getElementById("helloButton");
                  helloButton.addEventListener("click", this.buttonClickHandler, false);
      
                  // Retrieve the input element and register our
                  // event handler.
                  var nameInput = document.getElementById("nameInput");
                  nameInput.addEventListener("change", this.nameInputChanged);
      
                  // Restore app data. 
                  var roamingSettings = Windows.Storage.ApplicationData.current.roamingSettings;
      
                  // Restore the user name.
                  var userName =
                      Windows.Storage.ApplicationData.current.roamingSettings.values["userName"];
                  if (userName) {
                      nameInput.value = userName;
                  }
      
                  // Restore the rating. 
                  var greetingRating = roamingSettings.values["greetingRating"];
                  if (greetingRating) {
                      ratingControl.userRating = greetingRating;
                      var ratingOutput = document.getElementById("ratingOutput");
                      ratingOutput.innerText = greetingRating;
                  }
      
                  // If the app was terminated last time it ran, restore the personalized
                  // greeting. 
                  if (
                      WinJS.Application.sessionState.previousExecutionState
                      === Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                      var outputValue = WinJS.Application.sessionState.greetingOutput;
                      if (outputValue) {
                          var greetingOutput = document.getElementById("greetingOutput");
                          greetingOutput.innerText = outputValue;
                      }
      
                  }
      
              },
      
      
  3. 运行应用。现在,我们复制了在原始的“Hello, world”""应用中拥有的功能。

步骤 5:添加其他页面

大多数应用都包含多个页面。让我们向我们的应用中添加其他面。由于我们使用的是“导航应用”模板,因此添加其他页面会非常简单。

JJ663505.wedge(zh-cn,WIN.10).gif添加其他页面的步骤

  1. 在“解决方案资源管理器”中,右键单击“页面”文件夹,然后选择“添加”>“新建文件夹”。项目中将出现一个新的文件夹。
  2. 将该文件夹重命名为 "page2"。
  3. 右键单击 page2 文件夹,然后选择“添加”>“新建项...”。即会出现“添加新项”对话框。
  4. 从列表中选择“页面控件”。在“名称”文本框中,输入 "page2.html"。

  5. 单击“添加”以添加 PageControl。新的 PageControl 将出现在“解决方案资源管理器”中。

    HelloWorldWithPages 项目

    新的 PageControl 具有三个文件: page2.css、page2.html 和 page2.js。

  6. 在 page2.html 文件中,替换对深色样式表的引用:
    
    
        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.2.0/css/ui-dark.css" rel="stylesheet" />
    
    
    

    使用此表:

    
    
        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.2.0/css/ui-light.css" rel="stylesheet" />
    
    
    

现在,你已经创建了一个新页面。在下面的步骤中,你将学习如何导航到该页面。

步骤 6:使用导航函数在页面之间移动

现在,我们拥有了另一个页面,但用户无法到达该页面。让我们添加指向 page2.html 的链接来更新我们的 home.html 页面。

JJ663505.wedge(zh-cn,WIN.10).gif在页面之间导航的步骤

  1. 打开 home.html 并将链接添加到 page2.html。
    
    <body>
        <!-- The content that will be loaded and displayed. -->
        <div class="fragment homepage">
            <header aria-label="Header content" role="banner">
                <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
                <h1 class="titlearea win-type-ellipsis">
                    <span class="pagetitle">Hello, world!</span>
                </h1>
            </header>
            <section aria-label="Main content" role="main">
     
                <p>What's your name?</p>
                <input id="nameInput" type="text" />
                <button id="helloButton">Say "Hello"</button>
                <div id="greetingOutput"></div>
                <label for="ratingControlDiv">
                    Rate this greeting: 
                </label>
                <div id="ratingControlDiv" data-win-control="WinJS.UI.Rating">
                </div>
                <div id="ratingOutput"></div>
    
                <!-- A hyperlink to page2.html. -->
                <p><a href="/pages/page2/page2.html">Go to page 2.</a></p>
            </section>
        </div>
    </body>
    
    
  2. 运行应用,并单击该链接。它看似工作正常:应用显示 page2.html。

    “添加新项”对话框

但是,存在一个问题:应用执行了顶级导航。代替从 home.html 导航到 page2.html,它从 default.html 导航到 page2.html。

执行一个顶级导航

而你想要的是用 page2.html 替换 home.html 的内容。

按照建议方式导航到 page2.html

幸运的是,PageControlNavigator 控件使得执行此类型的导航变得非常容易。PageControlNavigator 代码(在你的应用的 navigator.js 文件中)为你处理 WinJS.Navigation.navigated 事件。当发生该事件时,PageControlNavigator 将加载该事件所指定的页面。

当你使用 WinJS.Navigation.navigateWinJS.Navigation.backWinJS.Navigation.forward 函数进行导航时,发生 WinJS.Navigation.navigated 事件。

你需要自己调用 WinJS.Navigation.navigate 而不是使用超级链接的默认行为。你可以将该链接替换为一个按钮并使用该按钮的单击事件处理程序来调用 WinJS.Navigation.navigate。或者你也可以更改超级链接的默认行为,以便当用户单击某个链接时,应用使用 WinJS.Navigation.navigate 来导航到链接目标。 若要执行该操作,处理超级链接的 click 事件并使用该事件来停止超级链接的默认导航行为,然后调用 WinJS.Navigation.navigate 函数并将链接目标传递给它。

JJ663505.wedge(zh-cn,WIN.10).gif替代默认超级链接行为

  1. 在你的 home.js 文件中,为你的超链接定义一个 click 事件处理程序,并使其成为你的 PageControl 的成员。将它命名为 linkClickEventHandler 并添加到 nameInputChanged 处理程序后面。
    
    
            nameInputChanged: function (eventInfo) {
                var nameInput = eventInfo.srcElement;
    
                // Store the user's name for multiple sessions.
                var appData = Windows.Storage.ApplicationData.current;
                var roamingSettings = appData.roamingSettings;
                roamingSettings.values["userName"] = nameInput.value;
            },        
    
     
            linkClickEventHandler: function (eventInfo) {
    
            }
    
    
  2. 调用 preventDefault 方法以防止默认链接行为(直接导航到指定页面)。
    
    
            linkClickEventHandler: function (eventInfo) {
                eventInfo.preventDefault();
    
            }
    
    
  3. 检索触发了该事件的超链接。
    
    
            linkClickEventHandler: function (eventInfo) {
                eventInfo.preventDefault();
                var link = eventInfo.target;
    
            }
    
    
  4. 调用 WinJS.Navigation.navigate 函数并将链接目标传递给它。(你也可以传递描述该页状态的状态对象。有关详细信息,请参阅 WinJS.Navigation.navigate 页面。)
    
    
            linkClickEventHandler: function (eventInfo) {
                eventInfo.preventDefault();
                var link = eventInfo.target;
                WinJS.Navigation.navigate(link.href);
            }
    
    
  5. 在 home.js 文件的 ready 函数中,将事件处理程序附加到你的超级链接。

    WinJS 提供一个 WinJS.Utilities.query 函数,该函数可轻松检索页面上的很多元素。WinJS.Utilities.query 函数返回一个 QueryCollection,它提供用于附加和删除事件处理程序的其他方法。让我们使用 WinJS.Utilities.query 集合和 listen 方法来附加我们的 linkClickEventHandler

    
            // This function is called whenever a user navigates to this page. It
            // populates the page elements with the app's data.
            ready: function (element, options) {
                // TODO: Initialize the page here.
    
                WinJS.Utilities.query("a").listen("click", 
                    this.linkClickEventHandler, false);
    
    

    此方法的出色之处在于它将为页面上任意数量的链接工作。我们目前只有一个链接,通过该方法,我们可以添加更多链接并且我们无需更改我们的代码。

  6. 运行应用并单击 page2.html 的链接。

    此时,应用采用正确的方式显示 page2.html

    此时页面使用正确的导航模式显示。

    导航到 page2.html 之后的内容细分

步骤 7:为其他导航添加 NavBar

NavBar 类似于专用于导航命令的 AppBar。(实际上,NavBarAppBar 的子类。)它可以包含简单的链接列表,以及按类别组织的多个级别的链接。你可以使用以下方法填充 NavBar:硬编码条目、以编程方式更新它,或者使用数据绑定。

用户需要它时,NavBar 将显示在应用屏幕顶部。用户可以通过以下方式调用 NavBar:执行边缘轻扫、按 Windows 徽标键 + Z,或者右键单击。

NavBar 还支持垂直布局和拆分的导航项(具有子导航选项的导航项)。NavBar 可高度自定义:你可以使用 CSS 来设置 NavBar 及其内容的几乎任何方面的样式,并且还可以创建自定义导航项。

导航栏为 WinJS 控件。若要在 HTML 中声明一个导航栏,你需要使用以下语法:



<div id="navbar" data-win-control="WinJS.UI.NavBar">

</div>


NavBar 具有三个组件:

  • NavBar 自身。
  • NavBarContainer 对象,它包含导航项(NavBarCommand 对象),并支持分页以及平移和滚动。单个 NavBar 中可以具有一个或多个 NavBarContainer 对象。你可以使用 NavBarContainer 对象来定义导航选项的组。
  • 一个或多个 NavBarCommand 对象。 用户通过点击它们来进行导航。

下面是一个简单的 NavBar 示例:


<div id="NavBar" data-win-control="WinJS.UI.NavBar">
    <div id="GlobalNav" data-win-control="WinJS.UI.NavBarContainer">
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{
                label: 'Home',
                icon: WinJS.UI.AppBarIcon.home,
                location: '/html/home.html',
                splitButton: false
                }">
            </div>
            <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{
                label: 'Your apps',
                icon: WinJS.UI.AppBarIcon.favorite,
                location: '/html/yourapps.html',
                splitButton: false
                }">
            </div>
    </div>
</div>

我们的应用包含多个页面。我们应该在哪里添加导航栏?

  • 如果你的导航栏包含应用可用于每个页面的命令,则将其添加到 default.html 文件。
  • 如果你的导航栏因页面而异,则可以在每个 PageControl 对象中定义不同的应用栏。
  • 还可以在 default.html 中定义一个中心导航栏,然后在你加载不同的 PageControl 对象时进行修改。

让我们创建一个简单的允许用户在 home.html 和 page2.html 之间导航的导航栏。我们将在 default.html 文件中定义导航栏。

JJ663505.wedge(zh-cn,WIN.10).gif添加导航栏的步骤

  1. 打开 default.html 文件。将 NavBar 控件添加为 body 元素的第一个子项。

    
    
        <div id="navbar" data-win-control="WinJS.UI.NavBar">
    
        </div>
     
    
    
  2. 每个导航栏都包括一个或多个 NavBarContainer 对象。你可以使用 NavBarContainer 对象来定义导航选项的组。向你的导航栏添加 NavBarContainer

    
    
        <div id="navbar" data-win-control="WinJS.UI.NavBar">
            <div id="globalNav" data-win-control="WinJS.UI.NavBarContainer">
                   
            </div>
        </div>
     
    
    
  3. 每个 NavBarContainer 都包括一个或多个 NavBarCommand 对象。 用户通过点击它们来进行导航。将 NavBarCommand 对象添加到 NavBarContainer

    以下是要为每个 NavBarCommand 设置的属性:

    • label:要为该命令显示的标签。

    • icon:要为该命令显示的图标,或自定义 PNG 文件的路径。(有关图标值的列表,请参阅 AppBarIcon。)

    • location:要转到的位置。

    • splitButton:命令是否具有子菜单。(默认值为 false。)

    
    
        <div id="navbar" data-win-control="WinJS.UI.NavBar">
            <div id="globalNav" data-win-control="WinJS.UI.NavBarContainer">
                    <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{
                        label: 'Home',
                        icon: WinJS.UI.AppBarIcon.home,
                        location: '/pages/home/home.html',
                        splitButton: false
                        }">
                    </div>
                    <div data-win-control="WinJS.UI.NavBarCommand" data-win-options="{
                        label: 'Page 2',
                        icon: WinJS.UI.AppBarIcon.page,
                        location: '/pages/page2/page2.html',
                        splitButton: false
                        }">
                    </div>
            </div>
        </div>
     
    
    

    (以下示例将显示如何以内联方式定义 NavBarCommand 对象,但你也可以从数据源生成它们。关于示例,请参阅 HTML NavBar 示例。)

  4. 运行应用。若要显示该栏,请进行边缘轻扫,按 Win + Z,或单击鼠标右键。

    一个简单的应用栏

    如果你单击按钮,导航栏将自动调用 navigate 并将你带到该页面。

    你已声明导航栏。接下来,让我们设置它的样式。

  5. 打开你的 default.css 文件,在该文件的开始部分,为应用栏创建一种可更改其背景色的 CSS 样式。
    
    #navbar {
    
        background-color: #03abe2;
    }
    
    
    
  6. 运行应用。现在,你可以使用导航栏在两个页面之间进行导航。

    HelloWorldWithPages 应用现在具有一个应用栏

摘要

祝贺你完成第三个教程!你已经学习了如何创建使用“导航应用”模板的项目并且学习了如何使用 PageControl 对象。你还学习了如何创建应用栏。

下载示例

你是否遇到问题,或是需要检查你编写的代码?如果是,请下载“JavaScript 入门”示例

后续步骤

在此教程系列的下一部分,你会了解如何创建更为复杂的应用。转到第 4 部分:布局和视图

相关主题

JavaScript 入门:本系列教程的完整代码
使用 HTML、CSS 和 JavaScript(电子书)对 Windows 8 应用进行编程
面向设计人员
导航模式
命令模式
布局
中心
底部应用栏
顶部应用栏
后退按钮
中心控件指南
应用栏指南(Windows 应用商店应用)
使应用栏成为辅助应用栏
面向开发人员 (XTML)
导航和导航历史记录示例
添加应用栏
添加导航栏
在页面之间导航 (HTML)
HTML 中心控件示例
HTML AppBar 控件示例
HTML NavBar 控件示例
WinJS.UI.Hub object
WinJS.UI.AppBar object
WinJS.UI.NavBar object
WinJS.UI.BackButton object

 

 

显示:
© 2014 Microsoft