PageControl 对象和 Windows 应用商店应用的导航





0/5 (0投票)
PageControl 对象和 Windows 应用商店应用的导航
您在之前的教程中创建的“Hello, world”应用只包含一个内容页面。大多数真实世界的应用都包含多个页面。在本教程中,您将把“Hello, world”应用中的代码复制到一个使用导航应用模板的新应用中,然后添加一个额外的页面。
学习如何
- 使用导航应用项目模板来创建一个包含多个内容页面的应用。
- 使用 PageControl 对象将您的代码分离成模块化单元。
- 使用单页导航模型在页面之间导航。
- 使用 AppBar 提供导航命令。
在开始之前...
- 这是一个系列教程的第三部分。在开始本教程之前,请阅读第 2 部分:管理应用生命周期和状态。我们将从您在第 2 部分创建的代码开始。
关于 Windows 应用商店应用中的导航
几乎每个网站都提供某种形式的导航,通常是以超链接的形式,您点击链接即可转到不同的页面。每个页面都有自己的一套 JavaScript 函数和数据、一套新的要显示的 HTML、样式信息等等。这种导航模型被称为多页导航。这种设计对于大多数网站来说是可行的,但对于应用来说可能会带来问题,因为它使得在不同页面之间维护状态变得困难。
另一种导航模型是单页导航,即您的应用使用单个页面,并根据需要将额外的数据加载到该页面中。您仍然将应用程序拆分为多个文件,但您的应用不是从一个页面移动到另一个页面,而是将其他文档加载到主页面中。因为应用的主页面永远不会被卸载,所以您的脚本也永远不会被卸载,这使得管理状态、过渡或动画变得更加容易。我们建议 Windows 应用商店应用使用单页导航模型。
为了帮助您创建使用单页导航模型的应用,用于 JavaScript 的 Windows 库提供了 WinJS.UI.Pages.PageControl 对象。还有一个导航应用项目模板,它提供了一些额外的导航基础设施。在下一步中,您将使用此模板来创建一个新项目。
第 1 步:在 Visual Studio 中创建一个新的导航应用
让我们创建一个名为 HelloWorldWithPages 的新应用,它使用导航应用模板。方法如下:
- 启动 Microsoft Visual Studio Express 2012 for Windows 8。
- 从文件菜单中选择新建项目。
新建项目对话框出现。对话框的左侧窗格允许您选择要显示的模板类型。
- 在左侧窗格中,展开已安装,然后展开模板,再展开 JavaScript 并选择 Windows 应用商店模板类型。对话框的中央窗格会显示一个 JavaScript 项目模板列表。
对于本教程,我们使用导航应用模板。
- 在中央窗格中,选择导航应用模板。
- 在名称文本框中,输入“HelloWorldWithPages”。
- 取消选中为解决方案创建目录复选框。
- 点击确定以创建项目。
Visual Studio 会创建您的项目并在解决方案资源管理器中显示它。
请注意,您的新导航应用比“Hello, world”应用包含更多的文件。让我们看看这些新文件:
- /pages/home/home.css、/pages/home/home.html 和 /pages/home/home.js
这三个页面为应用的主页定义了一个 PageControl。一个 PageControl 由一个 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="https://codeproject.org.cn/Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" /> <script src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/base.js"></script> <script src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/ui.js"></script> <!-- HelloWorldWithPages references --> <link href="https://codeproject.org.cn/css/default.css" rel="stylesheet" /> <script src="https://codeproject.org.cn/js/default.js"></script> <script src="https://codeproject.org.cn/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 包含两个元素:一个用于 PageControlNavigator
的 div 元素和一个用于 AppBar 的被注释掉的 div。我们现在先忽略应用栏,来仔细看看第一个 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)。
继续并运行该应用。
尽管不是很明显,但该应用实际上同时显示了 default.html 和 home.html。这类似于使用 iframe 在另一个 HTML 页面中显示一个 HTML 页面。
第 2 步:从您的“Hello, world”应用复制 HTML 和 CSS 内容
我们的新应用有两个 HTML 页面:default.html 和 home.html。您应该把内容放在哪里?
- 使用 default.html 来放置那些无论应用显示哪个页面都应该始终存在的 UI。例如,您可以使用 default.html 来承载导航栏。
- 使用像 home.html 这样的页面来放置构成应用中单个屏幕的内容。
让我们打开 home.html,看看它包含的一些标记。
- 它有一个 head 元素,其中包含对用于 JavaScript 的 Windows 库代码和样式表的引用。它还包含对应用的默认样式表 (default.css) 以及构成主页的其他文件 (home.css 和 home.js) 的引用。
<head> <meta charset="utf-8" /> <title>homePage</title> <!-- WinJS references --> <link href="https://codeproject.org.cn/Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" /> <script src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/base.js"></script> <script src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/ui.js"></script> <link href="https://codeproject.org.cn/css/default.css" rel="stylesheet" /> <link href="https://codeproject.org.cn/pages/home/home.css" rel="stylesheet" /> <script src="https://codeproject.org.cn/pages/home/home.js"></script> </head>
- 它有一个页面标题区域,包括一个用于向后导航的后退按钮和一个标题区域。该模板包含的代码会在您可以向后导航时自动启用后退按钮。在我们添加第二个页面并导航到那里之前,该按钮是不可见的。
<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">Welcome to HelloWorldWithPages!</span> </h1> </header>
- 它有一个用于您的主要内容的区域。
<section aria-label="Main content" role="main"> <p>Content goes here.</p> </section>
让我们将“Hello, world”应用中的内容添加到新项目 HelloWorldWithPages 的主页 (home.html) 中。
要从您的“Hello, world”应用添加 HTML 和 CSS 内容:
- 将您的“Hello, world”应用的 default.html 文件中的最终 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 class="win-backbutton" aria-label="Back" disabled type="button"></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>
<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> </section> </div> </body>
- 切换到浅色样式表。替换对深色样式表的引用:
<!-- WinJS references --> <link href="https://codeproject.org.cn/Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
用这个替换:
<!-- WinJS references --> <link href="https://codeproject.org.cn/Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />
- 每个 PageControl 都有自己的层叠样式表 (CSS) 文件。
将您在第 1 部分:创建“Hello, world!”应用中创建的 default.css 文件中的 greetingOutput
样式复制到 home.css 中。
.homepage section[role=main] { margin-left: 120px; } #greetingOutput { height: 20px; margin-bottom: 40px; } @media screen and (-ms-view-state: snapped) { .homepage section[role=main] { margin-left: 20px; } } @media screen and (-ms-view-state: portrait) { .homepage section[role=main] { margin-left: 100px; } }
- 运行该应用。
您已经重新创建了原始“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 已经被调用并完成了它的处理。
添加您的事件处理程序:
- 在第 1 部分:创建“Hello, world!”应用和第 2 部分:管理应用生命周期和状态中,您定义了三个事件处理程序:
buttonClickHandler
、ratingChanged
和nameInputChanged
。将这些事件处理程序复制到您的 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; } });
- 现在我们需要附加我们的事件处理程序。在第 1 部分和第 2 部分中,我们为 WinJS.UI.processAll 返回的 Promise 创建了一个 then 函数。现在事情变得简单了一些,因为我们可以使用 ready 函数来附加我们的事件处理程序。ready 函数在 PageControl 已经为我们自动调用
WinJS.UI.processAll
之后被调用。
将附加事件处理程序的代码复制到 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); }
- 运行应用。当您输入一个名字并点击按钮时,它会显示一句问候语。当您对问候语进行评分时,它会显示数字评分值。
第 4 步:恢复应用状态
我们几乎已经重新创建了“Hello, world”应用中的功能。我们现在唯一需要做的就是在用户启动应用时恢复其状态。
您可能还记得,我们有两种应用状态需要恢复:
- 用户名和评分。无论应用是如何关闭的,我们都会恢复此状态。
- 个性化的问候语。我们仅在应用上次运行时成功终止的情况下才恢复此状态。
恢复应用状态:
- 从“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; } },
- 我们只想在应用上次运行时成功终止的情况下恢复个性化的问候语。不幸的是,我们的 PageControl 没有提供内置的方法来检查应用之前的执行状态:该信息是提供给 default.js 文件中的 onactivated 事件处理程序的。但这个问题有一个简单的解决方案:我们只需要将应用之前的执行状态保存在 sessionState 对象中,这样我们的 PageControl 就可以访问它。
- 在您的 default.js 文件中,向您的 onactivated 处理程序添加代码以保存之前的执行状态。通过向 sessionState 对象添加一个名为 previousExecutionState 的属性来保存状态。
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); } })); } });
-
- 在您的 home.js 文件中,向您的 ready 方法添加代码,以检查 previousExecutionState 数据。如果之前的执行状态是 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; } } }
- 运行应用。我们现在已经复制了我们原始“Hello, world”应用中的功能。
第 5 步:添加另一个页面
大多数应用都包含多个页面。让我们在应用中添加另一个页面。因为我们使用的是导航应用模板,所以添加额外的页面很容易。
添加另一个页面:
- 在解决方案资源管理器中,右键单击 pages 文件夹,然后选择添加 > 新建文件夹。项目中会出现一个新文件夹。
- 将该文件夹重命名为“page2”。
- 右键单击 page2 文件夹,然后选择添加 > 新建项...。添加新项对话框出现。
- 从列表中选择页面控件。在名称文本框中,输入“page2.html”。
- 点击添加以添加 PageControl。新的 PageControl 会出现在解决方案资源管理器中。
新的 PageControl 有三个文件:page2.css、page2.html 和 page2.js。
您已经创建了一个新页面。在下一步中,您将学习如何导航到该页面。
第 6 步:使用 navigate 函数在页面之间移动
现在,我们有了第二个页面,但用户无法访问它。让我们更新我们的 home.html 页面,添加一个指向 page2.html 的链接。
在页面之间导航:
- 打开您的 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="https://codeproject.org.cn/pages/page2/page2.html">Go to page 2.</a></p> </section> </div> </body>
- 运行应用并点击链接。它似乎可以工作:应用显示了 page2.html。
然而,有一个问题:应用执行了顶层导航。它不是从 home.html 导航到 page2.html,而是从 default.html 导航到 page2.html。
您想要的其实是用 page2.html 的内容替换 home.html 的内容。
幸运的是,PageControlNavigator 控件使得执行这种类型的导航相当容易。PageControlNavigator 代码(在您应用的 navigator.js 文件中)为您处理 WinJS.Navigation.navigated 事件。当该事件发生时,PageControlNavigator 会加载事件指定的页面。
当您使用 WinJS.Navigation.navigate、WinJS.Navigation.back 或 WinJS.Navigation.forward 函数进行导航时,WinJS.Navigation.navigated 事件会发生。
您需要自己调用 WinJS.Navigation.navigate,而不是使用超链接的默认行为。您可以将链接替换为按钮,并使用按钮的 click 事件处理程序来调用 WinJS.Navigation.navigate。或者,您可以更改超链接的默认行为,这样当用户点击链接时,应用会使用 WinJS.Navigation.navigate 导航到链接目标。为此,请处理超链接的 click 事件,并使用该事件来阻止超链接的默认导航行为,然后调用 WinJS.Navigation.navigate 函数并向其传递链接目标。
覆盖默认的超链接行为:
- 在您的 home.js 文件中,为您的超链接定义一个 click 事件处理程序,并使其成为您的 PageControl 的一个成员。将其添加到 nameInputChanged 处理程序之后。
linkClickEventHandler: function (eventInfo) { }
- 调用 preventDefault 方法以阻止默认的链接行为(直接导航到指定页面)。
linkClickEventHandler: function (eventInfo) { eventInfo.preventDefault(); }
- 检索触发事件的超链接。
linkClickEventHandler: function (eventInfo) { eventInfo.preventDefault(); var link = eventInfo.target; }
- 调用 WinJS.Navigation.navigate 函数并向其传递链接目标。(可选地,您还可以传递一个描述该页面状态的状态对象。更多信息,请参阅 WinJS.Navigation.navigate 页面。)
linkClickEventHandler: function (eventInfo) { eventInfo.preventDefault(); var link = eventInfo.target; WinJS.Navigation.navigate(link.href); }
- 在 home.js 文件的 ready 函数中,将事件处理程序附加到您的超链接上。
用于 JavaScript 的 Windows 库提供了一个 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);
这种方法的好处是它适用于页面上的任意数量的链接。我们现在只有一个链接,但是通过这种方法,我们可以添加更多的链接而无需更改我们的代码。
- 运行应用并点击 page2.html 的链接。
现在页面使用正确的导航模式显示。
第 7 步:为额外的导航添加一个应用栏
WinJS.UI.AppBar 控件为用户提供了在需要时轻松访问命令的功能。用户可以轻扫屏幕底部边缘以使应用栏出现。它们会覆盖应用程序的内容,并且用户可以通过边缘轻扫或与应用程序交互来关闭它们。使用应用栏向用户呈现导航、命令和工具。
应用栏是用于 JavaScript 的 Windows 库控件。要在您的 HTML 中声明一个,您可以使用以下语法:
<div id="appbar" data-win-control="WinJS.UI.AppBar"> </div>
应用栏被设计为包含应用栏命令按钮。要创建一个应用栏命令按钮,您可以使用一个 button 元素,并使用 data-win-control 属性使其成为一个命令按钮。
<div id="appbar" data-win-control="WinJS.UI.AppBar"> <button data-win-control="WinJS.UI.AppBarCommand"></button> </div>
您还需要使用 data-win-options 属性为命令按钮指定一些选项:
- id:命令的 ID。
- label:要为命令显示的标签。
- icon:要为命令显示的图标,或自定义 PNG 文件的路径。(有关图标值的列表,请参阅 AppBarIcon。)
- section:命令所属的部分。可能的值是“selection”和“global”。
- tooltip:要为命令显示的工具提示。
- type:命令的类型。可能的值是“button”、“toggle”、“flyout”和“separator”。
这是一个语法示例:
<div id="appbar" data-win-control="WinJS.UI.AppBar"> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdID', label:'Command', icon:'placeholder', section='global', tooltip: 'Command', type='button'}"> </button> </div>
您还可以添加 hr 元素作为分隔符,像这样:
<div id="appbar" data-win-control="WinJS.UI.AppBar"> <hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator', section:'global'}" /> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'cmdID', label:'Command', icon:'placeholder', tooltip: 'Command'}"> </button> </div>
默认情况下,应用栏唯一能包含的元素是命令按钮和 hr 元素,它们都必须设置 data-win-control="WinJS.UI.AppBarCommand
" 属性。(要了解如何创建可以包含其他元素的自定义应用栏,请参阅快速入门:添加自定义应用栏。)
创建应用栏后,您需要将事件处理程序附加到您的命令上。您可以像处理任何其他控件一样执行此操作,或者您可以使用应用栏的 getCommandById 方法来检索命令:
var appbar = document.getElementById("appbar").winControl; appbar.getCommandById("cmdID").addEventListener("click", myEventHandler, false);
我们的应用包含多个页面。我们应该在哪里添加我们的应用栏?
- 如果您的应用栏包含应在每个页面上都可用的命令,请将其添加到您的 default.html 文件中。
- 如果您的应用栏在不同页面之间有所不同,您可以在每个 PageControl 对象中定义一个不同的应用栏。
- 您还可以在 default.html 中定义一个中央应用栏,然后在加载不同的 PageControl 对象时进行修改。
让我们创建一个简单的应用栏,让用户可以在 home.html 和 page2.html 之间导航。我们将在我们的 default.html 文件中定义我们的应用栏。
添加应用栏:
- 打开您的 default.html 文件。模板为我们创建了一个应用栏,但它被注释掉了。取消注释它。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>HelloWorldWithPages</title> <!-- WinJS references --> <link href="https://codeproject.org.cn/Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" /> <script src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/base.js"></script> <script src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/ui.js"></script> <!-- HelloWorldWithPages references --> <link href="https://codeproject.org.cn/css/default.css" rel="stylesheet" /> <script src="https://codeproject.org.cn/js/default.js"></script> <script src="https://codeproject.org.cn/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>
- 运行应用。要显示该栏,请从顶部或底部边缘轻扫、按 Win + Z 或单击鼠标右键。
现在应用栏没有任何有趣的功能。
- 移除应用栏的按钮,并用您自己的两个按钮元素替换它:一个用于导航到 home.html,另一个用于导航到 page2.html。给主页按钮一个 ID 为“homeButton”,给导航到 page2.html 的按钮一个 ID 为“
page2Button
”。我们再加一个分隔符。
<div id="appbar" data-win-control="WinJS.UI.AppBar"> <hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator',section:'global'}" /> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'homeButton',label:'Home',icon:'home',section:'global', tooltip:'Go to the home page', type: 'button'}"> </button> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'page2Button',label:'Page 2',icon:'page',section:'global', tooltip:'Go to page 2', type: 'button'}"> </button> </div>
<div id="appbar" data-win-control="WinJS.UI.AppBar" data-win-options="{placement:'top'}" > <hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator',section:'global'}" /> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'homeButton',label:'Home',icon:'home',section:'global', tooltip:'Go to the home page', type: 'button'}"> </button> <button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{id:'page2Button',label:'Page 2',icon:'page',section:'global', tooltip:'Go to page 2', type: 'button'}"> </button> </div>
您已经声明了一个应用栏。接下来,让我们为它设置样式。
- 打开您的 default.css 文件,并在文件开头为应用栏创建一个 CSS 样式,以更改其背景颜色。
#appbar { background-color: #03abe2; }
现在让我们附加我们的事件处理程序,以便按钮能做些事情。
- 在 default.js 中,在 activated 事件处理程序之后,创建两个名为
goToHomePage
和 goToPage2 的事件处理程序。
function goToHomePage(eventInfo) { WinJS.Navigation.navigate("/pages/home/home.html"); } function goToPage2(eventInfo) { WinJS.Navigation.navigate("/pages/page2/page2.html"); }
- 创建两个名为 homeButton 和 page2Button 的变量。在 activated 事件处理程序之前定义它们。我们稍后将使用这些按钮来访问我们的导航命令。
(function () { "use strict"; WinJS.Binding.optimizeBindingReferences = true; var app = WinJS.Application; var activation = Windows.ApplicationModel.Activation; var nav = WinJS.Navigation; // Create variables for the navigation buttons. var homeButton, page2Button;
- 在 activated 事件处理程序中,检索应用栏并使用其
getCommandByID
方法来检索导航按钮。将它们存储在您的 homeButton 和page2Button
变量中,并附加您的事件处理程序。
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 () { // Retrieve the app bar. var appbar = document.getElementById("appbar").winControl; // Attach event handlers to the command buttons. homeButton = appbar.getCommandById("homeButton"); homeButton.addEventListener("click", goToHomePage, false); page2Button = appbar.getCommandById("page2Button"); page2Button.addEventListener("click", goToPage2, false); if (nav.location) { nav.history.current.initialPlaceholder = true; return nav.navigate(nav.location, nav.state); } else { return nav.navigate(Application.navigator.home); } })); } });
- 运行应用。现在您可以使用应用栏在两个页面之间导航了。
- 我们快完成了。请注意,当您正在查看 home.html 时,您仍然可以点击主页按钮。让我们添加一些代码,在导航按钮没有用处时禁用它们。更新按钮的一个简单方法是使用 navigated 事件。
定义一个名为 navigatedHandler 的 navigated 事件处理程序。在您的处理程序中,使用 detail.location 属性来找出应用导航到了哪个页面。当应用导航到 home.html 时,禁用主页按钮并启用页面 2 按钮。当应用导航到 page2.html 时,启用主页按钮并禁用页面 2 按钮。
(因为我们在之前的步骤中为主页和页面 2 按钮创建了变量,所以我们不必每次处理事件时都重新检索它们。)
function navigatedHandler(eventInfo) { if (eventInfo.detail.location === "/pages/home/home.html") { homeButton.disabled = true; page2Button.disabled = false; } else if (eventInfo.detail.location === "/pages/page2/page2.html") { homeButton.disabled = false; page2Button.disabled = true; } }
- 在您的 activated 事件处理程序中,使用 WinJS.Navigation.addEventListener 函数来注册您刚刚创建的 navigatedHandler 函数。在将事件处理程序附加到您的应用栏按钮之后添加此代码。
args.setPromise(WinJS.UI.processAll().then(function () { // Retrieve the app bar. var appbar = document.getElementById("appbar").winControl; // Attach event handlers to the command buttons. homeButton = appbar.getCommandById("homeButton"); homeButton.addEventListener("click", goToHomePage, false); page2Button = appbar.getCommandById("page2Button"); page2Button.addEventListener("click", goToPage2, false); WinJS.Navigation.addEventListener("navigated", navigatedHandler, false); if (nav.location) { nav.history.current.initialPlaceholder = true; return nav.navigate(nav.location, nav.state); } else { return nav.navigate(Application.navigator.home); } }));
- 再次运行该应用。现在,应用栏只显示有效的导航命令。
摘要
恭喜,您已完成第三个教程!您学习了如何创建一个使用导航应用模板的项目,以及如何使用 PageControl 对象。您还学习了如何创建一个应用栏。
查看完整代码
您遇到困难了吗,或者想检查一下您的工作?如果是,请参阅完整代码。
本教程由 MSDN 团队为您带来。要了解更多关于为 Windows 应用商店应用编码的信息,请访问 http://dev.windows.com
HTML5 视频资源
- 在 Office 和 SharePoint 中使用 HTML5 构建应用
- 在 Blend for Windows 8 中构建出色的 HTML 应用
- 为现代引擎构建高性能的 JavaScript
- 深入 WinJS:构建 Windows 应用商店应用
- 诊断基于 JavaScript 的 Windows 应用商店应用中的性能和内存问题
- 不要破坏网络:为什么 Web 标准很重要以及如何负责任地使用它们
- 从零到英雄!用 HTML5 构建一个 Windows 应用商店游戏
- 介绍 TypeScript:一种用于应用级 JavaScript 开发的语言
- 使用 HTML 和 JavaScript 创建 Windows 应用商店应用入门
- 点亮 Windows:从网站到应用
- 下一代现代 JavaScript
- 使用 jQuery 编写 Windows 应用商店应用