1.4 导航

在页面之间导航不是新的概念,事实上,这就是超文本标记语言(HTML)中的超文本部分。当用户点击链接(或者带有onclick处理程序的HTML元素)时,我们通常要为用户呈现一个充满了数据、控件、图片等元素的全新页面。在浏览器中,这种情况下我们绝大多数时候都会下载一个全新的页面,把屏幕和所有的当前状态清空;而我们在Windows应用商店应用程序中进行导航的方式和浏览器也是一样的,但通常更喜欢使用WinJS中内置的导航服务,这样在页面间移动的时候对UI可以有更出色的控制,并且还可以让我们一直保持所构建的应用程序状态,就像订阅源的列表那样。

但是,不管我们想要导航到哪,都需要先确定导航的目的地。为此,必须在Visual Studio中的“解决方案资源管理器”(Solution Explorer)里面,找到项目并在"pages"目录上单击右键,选择“添加”(Add)|“新建文件夹”(New Folder)来为页面添加一个新的目录,命名为postsPage。这个目录将存放所有新页面的文件,要添加文件到其中可以在目录上单击右键,选择“添加”(Add)|“新建项”(New Item),然后从JavaScript|“Windows应用商店”(Windows Store)类别中选择“页面控制”(Page Control)项。如图1.19所示。

图1.19 Windows应用商店应用程序的Add New Item(添加新项)对话框

无论选择Windows应用商店类别下的哪一个模板项,都会生成三个文件:一个HTML文件、一个CSS文件和一个JavaScript文件,它们构成了适用于WinJS导航的页面控制。“页面控制”模板创建了一个空白的页面控制,而其他的三个模板可以帮助实现shell协定,这方面的内容参见第9章。

输入名称,例如postsPage.html,按下“添加”(Add)按钮,为页面控制创建三个新的文件,如图1.20所示。

图1.20 添加到Windows应用商店应用程序中的新的页面控制

这就是让一个页面成为导航目标需要做的全部事情——问题是,我们如何执行导航呢?在ListView的例子中,我们要让ListView知道,如果其中有某一项被调用时,就要给我们发送通知,下面的代码就实现了这一功能。

还记得我们什么时候在Blend里面把ListView控件添加到设计界面上的吗?是在添加了div并设置了data-win-control和data-win-options属性的时候。div代表HTML DOM中的WinJS控件,而WinJS.UI.ListView则是JS构造函数的名称(这些内容可以在第2章中学到),其中还有我们在Blend的属性面板中设置的itemDataSource和itemTemplate设定项。

其实完全没有必要使用Blend来对这些属性进行编辑,使用你最喜爱的文本编辑器也完全可以做到。在这个例子中,我们需要把“选择模式”(selection mode)设置为none(我们不需要选择,只想调用),我们要设置用户打开某一项时需要调用的处理程序的名称。这一处理程序是在相应的JavaScript文件中实现的:

feedInvoked处理程序被封装在eventHandler函数中,表明从home.html文件中的data-win-options使用它是安全的。这是一种安全措施,保证从Internet上下载的HTML代码不会对应用程序进行劫持。

feedInvoked处理程序的实现过程是,在event对象的detail属性中找出被调用的项的索引,这个feed对象会通过navigate方法被传递给postsPage;之后,WinJS的导航服务会加载postsPage,并且通过options参数把feed对象传递给ready函数。

现在我们已经在ListView上设置了一个调用的处理程序,在主页(图1.21)上单击一个订阅源的标题,就会把我们带到之前构建的显示订阅源文章的页面上(图1.22)。

图1.21 在ListView控件上触发调用事件

图1.22 使用WinJS导航服务导航到一个页面控制上

现在你也许会注意到,虽然“返回”按钮元素出现在home.html中,却没有出现在图1.21当中,但出现在了图1.22所示的postPage.html中。这是因为模板提供的导航支持足够智能,知道主页没有可以返回的历史页面,所以它只会在有“返回”的地方显示“返回”按钮。此外,虽然无法看到,但模板同样支持浏览器上所支持的“返回”和“向前”的键盘快捷键(如Alt+左箭头和Alt+右箭头)。

这就意味着你可以把页面写成页面控制并且进行对象的传递,而让模板的导航支持去处理那些比较难的部分。

当然,对于我们的RSS阅读器,现在仍是连基本的功能都没有实现,因为我们仍然没有从选中的订阅源去下载文章。要实现这一功能,我们还得写一小段网络连接的代码。