快速入门:使用单页导航 (HTML)
[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]
了解单页导航模型,以及如何通过使用 PageControl 对象和 WinJS.Navigation 功能在自己的应用中实现该模型。
有关为你的应用选择最佳导航模式的帮助,请参阅导航模式。
同样,你可以在操作时参阅平面导航和分层导航模式,它们是应用功能大全系列的一部分。
先决条件
我们假设你了解如何创建基本应用。如果你需要相关帮助,请参阅创建你的第一个使用 JavaScript 的应用。
我们假设你熟悉如何使用 Windows JavaScript 库控件。有关如何使用 WinJS 的帮助,请参阅快速入门:添加 Windows JavaScript 库控件和样式。
创建基本的链接
最简单而且最常用的导航形式是超链接。以下 HTML 代码将会创建一个导航至 page2.html 的超链接。
<p><a href="page2.html">Go to page 2</a></p>
由于它是相对链接,因此系统会假定 page2.html 是你的应用中的一个本地页面,相对于当前文档的基础 URL。 例如,如果链接显示在 /folder/default.html 中,则单击该链接会将你带至 /folder/page2.html。
注意 如果你针对本地化优化了你的应用(通常最好这样做),该行为将根据 /folder/ 下已本地化的内容文件夹而有所不同。请参阅让你的应用全球化。
如果要为你的应用程序中的一个本地文件明确指定完整的 URI,使用新的已打包内容 URL 方案 (ms-appx),如下所示:
- **ms-appx://package name/**file path
如果希望省略应用包名称,你可以这样做。
- **ms-appx:///**file path
下面提供了一个示例。
<p><a href="ms-appx:///page2.html">Go to page 2</a></p>
在引用应用包中所包含的任何文件时,你可以使用 ms-appx URL 方案。然而,我们推荐使用相对 URL,因为会根据文档的基础 URL 自动解析这些 URL。
单页面导航:推荐的模式
上一个示例向你显示了如何创建可以执行顶级导航的链接。这适用于网页,但你不应在应用中执行顶级导航,有以下几个原因:
- 当应用加载下个页面时,屏幕将为空。
- 脚本上下文将被破坏,并且必须重新初始化。应用可能会接收系统事件,但无法处理这些事件,因为脚本上下文被破坏和重新初始化。
与顶级导航相比,使用单页导航可提供更好的性能和更类似于应用的使用体验。新的 Microsoft Visual Studio 项目中不会自动提供导航控件,因此对新页面的顶级导航是指无法返回到第一个页面,除非你手动创建一个链接或其他导航机制来执行返回操作。而且,你只能在起始页指定应用如何管理其生命周期—当应用启动、关闭或暂停时有何行为。如果你有多个顶级页面,每个页面都必须包含管理应用的生命周期和状态的逻辑。
你应该使用哪一个控件将内容加载到主页?
- 你可使用文档对象模型 (DOM) 从其他来源加载文档。
- 对于简单的 HTML 内容(不包含脚本引用的非交互式内容),请使用 HtmlControl 对象。
- 对于外部 Web 内容,请尽可能使用 x-ms-webview 控件。与 iframe 相比,该控件提供更好的隔离、导航、SmartScreen 筛选器可用性以及对无法在 iframe 中托管的站点的支持。
- 对于所有其他内容,请使用 Page 控件。
Visual Studio 提供了一些适用于应用的 JavaScript 项目模板,可以使管理导航的工作变得更容易。这些项目模板提供了一个名为 PageControlNavigator 的导航控件,该控件用于在 PageControl 对象之间导航。 PageControlNavigator 类为你提供了一种可以使用 PageControl 来简化单页导航的方法。
以下步骤将会讲述如何创建包含多个 PageControl 对象的应用,以及如何使用单页导航模型在这些页面之间进行导航。
步骤 1:创建一个新的导航应用项目
启动 Microsoft Visual Studio 2013 Update 2。
注意 首次运行 Visual Studio 时,它会提示你获取开发人员许可证。
选择“文件”>“新建项目”或从“起始页”选项卡单击“新建项目”。将打开“新建项目”对话框。
在左侧的“模板”窗格中,依次展开“已安装”=>“模板”=>“JavaScript”=>“应用商店应用”****。
选择“通用应用”模板类型。JavaScript 可用的项目模板随即将显示在对话框的中心窗格中。
在中心窗格中,选择“导航应用(通用应用)”****项目模板。
在“名称”文本框中,键入项目名称。本主题中的示例使用 "NavigationAppExample"。
单击“确定”****以创建项目。
新建的“导航应用”项目包含一个起始页、一个主页和一些其他的支持文件。它在“解决方案资源管理器”中的外观如下所示。****
新的“导航应用”项目包括大量文件。一些文件特定于 Windows 应用,一些文件特定于 Phone 应用,还有一些文件用于共享。
该项目包括如下 HTML 文件:
- default.html—起始页。它最先被加载。它包含
PageControlNavigator
(将每一页加载到主窗口)的一个实例,并且你在其中创建 AppBar(如果你的应用使用它的话)。注意 HTML 页面将加载到单个内容主机中,它是在 default.html 中声明的一个 div 元素。在 default.html 中,使用 Windows JavaScript 库 (WinJS) 提供的 data-win-control 属性将内容主机 div 元素声明为PageControlNavigator
类型的控件。 - home.html—主页。它显示“欢迎”标题。
该项目包括如下 JavaScript 文件:
- default.js—指定应用启动时的行为。
- home.js—指定与主页相关联的行为。
- navigator.js—它能实现
PageControlNavigator
对象,该对象支持 Windows 应用商店应用 JavaScript 模板的导航模型。
该项目包括如下 CSS 文件:
- default.css—为内容主体页面和应用整体指定级联样式表 (CSS) 样式。
- home.css—为主页指定 CSS 样式。
该项目还包括 package.appxmanifest 文件,它可描述应用包。最后,该项目还包括多个图像文件,如用于初始屏幕图像的 splashscreen.png 以及用于 Windows 应用商店的 storelogo.png。
- default.html—起始页。它最先被加载。它包含
运行应用。选择“调试”>“启动调试”****,或者选择 F5(选择 SHIFT + F5 以停止调试并返回 Visual Studio)。
下面是 Windows 应用的屏幕截图。
下面是 Phone 应用的屏幕截图。
请注意,你现在看到的内容不是在 default.html 文件中定义的。它是在 home.html 文件(单独页面)中定义的。
PageControlNavigator
用于检索主页的内容并将其显示在 default.html 中。此处显示了导航控件
PageControlNavigator
。它定义了多个用于导航的函数。此控件在 navigator.js 中实现。WinJS.Namespace.define("Application", { PageControlNavigator: WinJS.Class.define( // Define the constructor function for the PageControlNavigator. function PageControlNavigator(element, options) { // Initialization code. }, { // Members specified here. } ), // . . . });
构造函数为导航控件执行初始化操作。少数重要初始化任务需要为 WinJS 事件(如 WinJS.Navigation.onnavigating 事件)设置处理程序以及设置应用的主页。(主页值在 data-win-options 属性的
contenthost
DIV 元素中指定。)// Initialization code. this.home = options.home; // . . . // The 'nav' variable is set to WinJS.Navigation. addRemovableEventListener(nav, 'navigating', this._navigating.bind(this), false); addRemovableEventListener(nav, 'navigated', this._navigated.bind(this), false);
声明为应用的导航控件(在 default.html 中)的 DIV 元素为所有应用的页面提供内容主机。DIV 元素使用 WinJS data-win-control 属性将自己声明为导航控件,此控件为应用提供导航模型。所有页面内容均加载到此 DIV。
以下是 default.html 页面的完整标记。
<!-- default.html --> <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>NavigationAppExample</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> <!-- NavigationAppExample 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'}"> </button> </div> --> </body> </html>
此图示显示了出现在应用的窗口中的不同内容单元:
在后续步骤中,你将了解关于使用 PageControlNavigator
和 PageControl 对象添加页面的详细信息。
步骤 2:创建一个新页面
PageControl 是 HTML、CSS 和 JavaScript 的一个模块化单元,用作逻辑页。
向 Visual Studio 2013 项目添加新页面时,需要执行以下操作:
- 在 Visual Studio 中使用“页面控件”项模板添加新页面。
- 使用 WinJS.Navigation.navigate 函数添加代码以导航到新页面。提示 此函数不会直接执行导航,但会调用在 navigator.js 中处理的 WinJS.Navigation.onnavigated 事件。navigator.js 中的代码会在新页面中调用 ready 函数。通常,无需修改 navigator.js。
- 如有必要,可添加应用相应的 UI 和事件处理程序,以调用页面导航代码。
页面有一组预定义的方法,库以预定义的顺序自动调用这些方法。WinJS.UI.Pages.define 函数为实现暴露这些方法。
添加页面
在“解决方案资源管理器”中,右键单击 pages 文件夹,选择“添加”****>“新建文件夹”。注意 对于此示例,我们添加了“已共享”页面。你可以根据需要将独特的页面添加到 Windows 或 Phone 项目。
将此新文件夹命名为 page2。
右键单击 page2 文件夹,然后选择“添加”>“新建项”****。
在“添加新项”对话框的中间窗格中,选择“页面控件”****。
将页面命名为 page2.html,然后选择“添加”。
将在 page2 文件夹中创建 page2.html 文件以及其他两个项目文件:page2.css 和 page2.js。这些文件加在一起代表一个逻辑页面。
提示 如果在项目的其他位置添加了项模板,则可能需要更新 page2.html 中的脚本和 CSS 参考。
打开 page2.js 并验证 define 函数中的 URI 是否正确。如下所示:
WinJS.UI.Pages.define("/pages/page2/page2.html", { // . . . ready: function (element, options) { // ready function implementation. }, // . . . });
步骤 3:自定义你的页面
现在,修改你的新页面,以使它显示不同的消息和周天。
打开 page2.html。页面控件项模板将会创建一个 HTML 页面,该页面包含头节(其中包含后退按钮)和页面的主要内容节。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>page2</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="page2.css" rel="stylesheet" /> <script src="page2.js"></script> </head> <body> <div class="page2 fragment"> <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 page2</span> </h1> </header> <section aria-label="Main content" role="main"> <p>Content goes here.</p> </section> </div> </body> </html>
用以下代码替换主要内容节。
<section aria-label="Main content" role="main"> <p>Page controls make it easy to divide your app into modular portions.</p> <p>Today is <span id="dayPlaceholder"></span>.</p> </section>
现在,你的 page2.html 文件应如下所示。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>page2</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="page2.css" rel="stylesheet" /> <script src="page2.js"></script> </head> <body> <div class="page2 fragment"> <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 page2</span> </h1> </header> <section aria-label="Main content" role="main"> <p>Page controls make it easy to divide your app into modular portions.</p> <p>Today is <span id="dayPlaceholder"></span>.</p> </section> </div> </body> </html>
打开 page2.js。PageControl 包含一组预定义的函数,它们会按照预定义的顺序自动调用。页面控件项模板为你包含 ready 函数以及
updateLayout
和unload
函数。当用户切换纵向和横向或者更改应用窗口大小时,
PageControlNavigator
会调用updateLayout
函数。 本主题不介绍如何如何定义updateLayout
,但是每个应用都应该执行此操作。请参阅调整窗口大小以适应较高和较窄布局的指南和通用 Windows 平台 (UWP) 应用的响应式设计基础知识。在以下时候调用 ready 函数:加载页面的 DOM,激活控件以及将页面加载到主 DOM 时。
(PageControl 支持其他用于页面生命周期的函数。有关详细信息,请参阅添加页面控件。)
下面是页面控件项模板创建的 page2.js 文件。
// page2.js (function () { "use strict"; WinJS.UI.Pages.define("/pages/page2/page2.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. }, unload: function () { // TODO: Respond to navigations away from this page. }, updateLayout: function (element) { /// <param name="element" domElement="true" /> // TODO: Respond to changes in layout. } }); })();
修改 ready 函数,以便它检索在步骤 2 中创建的跨度 ("dayPlaceholder") 并将其 innerText 设置为当前日。
// page2.js (function () { "use strict"; WinJS.UI.Pages.define("/pages/page2/page2.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. var dayPlaceholder = document.querySelector("#dayPlaceholder"); var calendar = new Windows.Globalization.Calendar(); dayPlaceholder.innerText = calendar.dayOfWeekAsString(); }, unload: function () { // TODO: Respond to navigations away from this page. }, updateLayout: function (element) { /// <param name="element" domElement="true" /> // TODO: Respond to changes in layout. } }); })();
你已经创建并自定义了一个页面。在下一步中,你将使用户能够在运行该应用时导航到你的页面。
步骤 4:使用导航函数在页面之间移动
当你现在运行该应用时,它将显示 home.html;用户无法导航到 page2.html。帮助用户到达 page2.html 的一种简单方法是从 home.html 链接到它。
<!-- home.html -->
<!DOCTYPE html>
<html>
<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>
<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 NavigationAppExample!</span>
</h1>
</header>
<section aria-label="Main content" role="main">
<p>Content goes here.</p>
<!-- A hyperlink to page2.html. -->
<p><a href="/pages/page2/page2.html">Go to page 2.</a></p>
</section>
</div>
</body>
</html>
如果你运行应用并单击链接,它好像有效:应用将显示 page2.html。问题是,应用执行的是一个顶级导航。它不是从 home.html 导航到 page2.html,而是从 default.html 导航到 page2.html。
而你想要的是用 page2.html 替换 home.html 的内容。
幸运的是,PageControlNavigator
控件使得执行此类型的导航变得非常容易。PageControlNavigator
代码(在你的应用的 navigator.js 文件中)为你处理 WinJS.Navigation.onnavigated 事件。当发生该事件时,PageControlNavigator
将加载该事件所指定的页面。
当你使用 WinJS.Navigation.navigate、WinJS.Navigation.back 或 WinJS.Navigation.forward 函数进行导航时,发生 WinJS.Navigation.navigated 事件。
你需要自己调用 WinJS.Navigation.navigate 而不是使用超级链接的默认行为。你可以将该链接替换为一个按钮并使用该按钮的单击事件处理程序来调用 WinJS.Navigation.navigate。或者你也可以更改超级链接的默认行为,以便当用户链接它时,应用使用 WinJS.Navigation.navigate 来转到链接目标。 若要执行该操作,处理超级链接的 click 事件并使用该事件来停止超级链接的默认导航行为,然后调用 WinJS.Navigation.navigate 函数并将链接目标传递给它。操作方法如下:
在 home.js 文件中,为超链接定义 click 事件处理程序。
function linkClickEventHandler(eventInfo) { }
调用 preventDefault 方法以防止默认链接行为(它会直接导航到指定页面)。
function linkClickEventHandler(eventInfo) { eventInfo.preventDefault(); }
检索触发了该事件的超链接。
function linkClickEventHandler(eventInfo) { eventInfo.preventDefault(); var link = eventInfo.target; }
调用 WinJS.Navigation.navigate 函数,并将链接目标传递到它。(你也可以选择传递描述该页状态的状态对象。有关详细信息,请参阅 WinJS.Navigation.navigate。)
function linkClickEventHandler(eventInfo) { eventInfo.preventDefault(); var link = eventInfo.target; WinJS.Navigation.navigate(link.href); }
在 home.js 的 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. WinJS.Utilities.query("a").listen("click", linkClickEventHandler, false); } });
这就是最后一步。以下是 home.js 文件的完整代码。
// 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.
WinJS.Utilities.query("a").listen("click", linkClickEventHandler, false);
}
});
function linkClickEventHandler(eventInfo) {
eventInfo.preventDefault();
var link = eventInfo.target;
WinJS.Navigation.navigate(link.href);
}
})();
运行应用并单击 page2.html 的链接。显示的内容如下。
这次使用正确的导航模式显示页面。
页面控件模板包括一个后退按钮,当你使用 WinJS.Navigation 函数进行导航时,它将处于启用状态。当你使用 WinJS.Navigation 函数时,应用将为你存储导航历史记录。 你可通过调用 WinJS.Navigation.back 使用该历史记录向后导航,或者通过调用 WinJS.Navigation.forward 向前导航。
注意 Windows 应用商店应用通常使用两种导航模式(平面和分层)之一。我们建议不要在平面导航应用中使用 BackButton 对象。有关详细信息,请参阅导航模式。
在你的应用暂停时保存导航历史记录
在你的应用暂停或关闭时,不会自动存储导航历史记录,但你自己可以方便地存储此信息。使用 WinJS.Navigation.history 属性可以检索和导航历史记录,使用 WinJS.Application.sessionState 对象可以存储历史记录。 为确保获得流畅的暂停/恢复体验,最好在用户每次导航时存储此信息。
当你的应用恢复时,从 WinJS.Application.sessionState 对象检索历史记录信息,并使用它设置 WinJS.Navigation.history 属性。
有关如何使用 WinJS.Application.sessionState 对象存储和恢复会话数据的示例,请参阅第 2 部分:管理应用生命周期和状态。有关暂停和恢复的详细信息,请参阅启动、恢复和多任务。
摘要
你已经学习了如何使用 WinJS.UI.Pages 命名空间的对象和方法来支持单页导航模型。
你已经学习了如何使用此单页导航模型来生成应用。你使用模板提供的 PageControlNavigator 类,在自己的应用中使用 PageControl 对象和 WinJS.Navigation 功能来实现此模型。
相关主题
面向开发人员
你的第一个应用 - 第 3 部分:PageControl 对象和导航
面向设计人员