HTML5

使用 Apache Cordova 开发 HTML5 Windows Phone 应用程序

Colin Eberhardt

下载代码示例

这篇文章介绍 Apache 科尔多瓦,创建使用 HTML5 和 JavaScript,跨平台移动应用程序的框架,并显示了如何使用它为 Windows Phone 开发应用程序。

Windows Phone 和其本机开发平台允许您轻松地创建美丽地铁样式的应用程序。 最近诺基亚的伙伴关系,与 Windows Phone 开始越来越多口袋找到出路。

最近的数据发表的研究公司 Gartner Inc. 预测微软操作系统的一个充满希望的未来 (bit.ly/h5Ic32),具有重大的市场零碎的市场份额。 如果您正在开发一个智能手机的应用程序,此市场碎片意味着您必须选择哪些目标或写入多次使用的语言范围很广的同一应用程序的操作系统,这些电话,要么要求 (C#、 Java 和目标 C)。

然而,有另一种方式。 所有这些智能手机有很强的浏览器,在很多方面更有能力桌面同行,其中一些人仍用古老的浏览器 ! 现代智能手机允许您创建使用 HTML5、 JavaScript 和 CSS 的组合在浏览器中运行的应用程序。 这些技术可以有可能编写跨多种不同的智能手机设备运行单个基于浏览器的应用。

引入 Apache 科尔多瓦

您可以创建基于 HTML5 的移动应用程序通过 JavaScript 和 HTML5 内容创建公共 Web 页并将用户引导到宿主的 URL。 然而,有几个使用这种方法的问题。 第一是通过在线市场和商店的分布模式。 您不能提交的 URL,那么如何你可以盈利它承载你到市场上的 Web 应用程序? 第二个问题是如何访问手机的硬件。 没有得到广泛支持的浏览器 Api,用于访问电话联系人、 通知、 照相机、 传感器等。 Apache 科尔多瓦 (以下简称为简洁起见只是科尔多瓦) 是一个自由和开放源码框架,解决了这两个问题。

科尔多瓦生命始于 PhoneGap,这由 Nitobi 开发的。 2011 年 10 月 Nitobi 与 PhoneGap 框架正在开源了 Apache 软件基金会根据 Adobe 系统公司被收购,作为科尔多瓦反攻。 这种转变是仍在进行。

科尔多瓦提供环境承载您薄的本机包装内的 HTML5/JavaScript 内容。 为每个智能手机操作系统,它使用一个本机浏览器控件呈现您的应用程序内容,与被打包成可发布的应用程序资产。 Windows Phone,与你 HTML5 资产打包在 XAP 文件和加载到独立存储科尔多瓦应用程序启动时。 在运行时,WebBrowser 控件呈现您的内容,并执行 JavaScript 代码。

科尔多瓦还提供一组标准的 Api,用于访问跨不同的智能手机是一样的功能。 这些功能包括:

  • 应用程序生命周期事件
  • 存储 (HTML5 本地存储和数据库)
  • “联系人”程序
  • 相机
  • 地理定位
  • 加速度计

每个前面的功能公开为 Java­脚本的 API,您从您的 JavaScript 代码使用。 科尔多瓦不会参与提供所需要的本机执行,确保您工作相同的 JavaScript Api,无论手机操作系统的针对您的代码的努力工作正在运行,如中所示的所有图 1

Cordova Allows the Same HTML5 Application to Run Across a Range of Mobile OSes
图 1 科尔多瓦允许跨范围的移动操作系统运行同一 HTML5 应用程序

这篇文章的大部分讨论科尔多瓦 Windows Phone 开发人员,在 Visual Studio 中发生的发展和您测试您的应用程序的物理设备或仿真程序上的视角。 科尔多瓦是跨平台技术,您通常开发使用您的编辑器或 IDE 的选择,因此一个 iOS 开发者将开发在 Xcode 科尔多瓦应用程序和一个 Android 开发者很可能会使用 Eclipse。

科尔多瓦也有称为生成基于云计算的生成服务 (build.phonegap.com),可以在此提交您的 HTML5/JavaScript 内容。 在短时间后,它返回的科尔多瓦支持平台的大部分分布。 这意味着您不需要为了生成应用程序的一系列平台的各种特定于平台的 Ide (或 Mac 计算机) 的副本。 生成服务是 Adobe 的财产和目前在 beta 版和免费使用。 它仍将免费开放源码项目。

获取工具

假定您已经有了 Visual Studio、 Windows Phone SDK 和 (可选) 为 Windows Phone 发展设置了 Zune。 如果不是,您可以获取工具免费下载 Visual Studio 2010 表示为 Windows Phone (bit.ly/dTsCH2)。

您可以从 PhoneGap 网站获取最新的科尔多瓦开发人员工具 (phonegap.com),尽管未来的版本将会通过 Apache 分发 (incubator.apache.org/cordova)。 下载内容包括模板、 图书馆和跨所有支持的平台开发科尔多瓦应用程序所需的脚本。 你要使用 Windows Phone 的版本,当然。

一旦您下载科尔多瓦工具,请按照 Windows Phone 获取启动指南 (phonegap.com/start#wp) 和安装 Visual Studio 模板。 创建"Hello World"-样式应用程序很简单,创建新的项目基于提供的模板,如图所示,在图 2

Cordova for Windows Phone Includes a Visual Studio Template
图 2 为 Windows Phone 科尔多瓦包括 Visual Studio 模板

如中所示如果您生成和部署您的仿真程序模板所创建的项目,你应将其热烈的消息"你好科尔多瓦," 图 3

The Cordova Template Application Running on an Emulator
图 3 运行模拟器上的科尔多瓦模板应用程序

Windows Phone 科尔多瓦应用解剖

虽然您可以开发多不知情的情况下科尔多瓦中应用的引擎罩下如何工作的是值得理解什么由模板生成的各种文件,如中所示图 4

The Cordova Template Folder Structure
图 4 科尔多瓦模板文件夹结构

只专注于中的科尔多瓦文件图 4 (从上到下),请注意下列事项:

  • GapLib/WP7CordovaClassLib.dll 是科尔多瓦大会。 这包含 Windows Phone 的本机实现的科尔多瓦 Api。
  • www 是您的应用程序资产,HTML5、 JavaScript、 CSS 和图像的放置位置的文件夹。 该模板生成一个基本的 index.html 文件和 master.css 样式表。
  • www/cordova-1.5.0.js 提供了 Windows Phone 上一篇­科尔多瓦 JavaScript Api 的心理状态。 此接口包含在 WP7CordovaClassLib 内的本机代码。
  • BuildManifestProcessor.js 是一个 JavaScript 文件,调用的后期生成步骤。 此文件生成科尔多瓦­SourceDictionary.xml 文件,确保任何您将添加到 www 文件夹将加载到独立存储。
  • CordovaSourceDictionary.xml 是生成的 XML 文件,其中列出所有您应用程序的资产。 当应用程序首次启动时,此 XML 文件指示要装入到独立存储文件。

MainPage.xaml 文件包含 CordovaView 控件,用户控件包含 WebBrowser 控件的实例:

<Grid x:Name="LayoutRoot">
    <my:CordovaView Name="PGView" />
  </Grid>

当应用程序启动时,CordovaView 控制照顾您应用程序的资产装入本地存储并导航到 www/index.html 文件,从而启动您的应用程序。 可以,当然,放置其他 Silverlight 控件在页中通过编辑 XAML 中,虽然我不会推荐它。 如果您编写的 HTML5 的应用程序,你的意图是可能使此工作跨平台。 当然,任何控件,您将添加到 MainPage.xaml 将特定于您的 Windows Phone 构建。

科尔多瓦应用程序开发

可以将您的 HTML、 JavaScript 和 CSS 文件添加 www 文件夹和 — — 只要你将它们标记与生成操作的内容 — — 当您的应用程序执行时,他们就会包括在您的项目中,并可通过浏览器控件访问。 可以在应用程序科尔多瓦中,只要他们是与手机的浏览器兼容使用任何 JavaScript/HTML5 标准库或框架。

科尔多瓦网站上记录了科尔多瓦 Api 我就不在这里详细描述他们。 要注意的一件重要的事情是,你必须等待之前制作的 deviceready 事件的任何其它 API 方法的使用。 如果您检查从模板生成的 index.html 文件,您可以看到它会等待直到设备准备好之前更新用户界面:

<script type="text/javascript">
  document.addEventListener("deviceready",onDeviceReady,false);
  function onDeviceReady()
  {
    document.getElementById("welcomeMsg").innerHTML
      += "Cordova is ready!
version=" + window.device.cordova;
    console.log(
      "onDeviceReady.
You should see this " +
        "message in Visual Studio's output window.");
  }
</script>

在前面的代码中使用的控制台对象允许您将添加到您的应用程序的调试输出。 科尔多瓦的情况下,这些消息发送到 Visual Studio 控制台。

单页或多页应用程序体系结构

当构建科尔多瓦的应用程序,您可以使用两种不同的模式:

  • 多页的应用程序:多个 HTML 页面在多页的应用程序,用于表示您的应用程序的各种屏幕。 页面之间的导航使用标准的浏览器的力学、 锚标签所定义的链接。 每个 HTML 页包含脚本的引用
  • 科尔多瓦 JavaScript 代码和 JavaScript 的应用程序。
  • 单页面的应用程序:在单页面应用中,单个 HTML 文件引用科尔多瓦和 JavaScript 的应用程序。 您的应用程序的各个页面之间的导航被通过呈现的 HTML 进行动态更新。 从手机浏览器的角度来看,URL 将保持不变,有没有页面之间的导航。

这两种模式之间所做的选择对您的代码的结构具有重大影响。

一般来说,多页的模式是最适合于主要包括静态内容的应用程序。 使用此方法时,您可以采取 HTML/CSS/JavaScript,目前用于您的 Web 站点并包装它,使用科尔多瓦,传送到手机作为一种应用。 但多页的方法有一些缺点。 第一,当浏览器从一个页面导航到下一个,它已重新加载和解析与新页相关联的所有 JavaScript。 有一个明显的暂停科尔多瓦生命周期,创建 JavaScript Api 与 C# 同行之间的联系,执行。 第二,因为重新加载您的 JavaScript 代码的所有应用程序状态会丢失。

单页面模式克服了多页的方法与相关的问题。 科尔多瓦和 JavaScript 代码的应用程序加载就一次,导致响应更快的用户界面中,不再需要将应用程序状态从一页传递到下一步。 这种方法的唯一缺点是增加了复杂性,与正在更新 UI 导航发生时所需的 JavaScript 代码。

本文中描述的演示应用程序使用单页面模式。 行动中的多页的方法的示例,我建议看看 DemoGAP CodePlex 项目 (demogap.codeplex.com),它提供了一个简单的演示 Windows Phone 应用程序内的科尔多瓦 API 功能。

演示应用程序

本文的其余部分描述了"科尔多瓦 Twitter 搜索,"一个简单的 Windows Phone 应用程序,允许用户在搜索 Twitter 基于一个或多个关键字,如图所示,在图 5

The Cordova Twitter Search Demo Application
图 5 科尔多瓦 Twitter 搜索演示应用程序

此应用程序,以及科尔多瓦,使得使用的下列框架:

  • jQuery,jQuery 的模板:jQuery 已经成为事实上的标准框架的浏览器文档对象模型 (DOM) 操作。 jQuery 模板是微软开发的插件 (bit.ly/8ZO2V1),就可以更轻松创建可重用可以呈现给 DOM 的 HTML 模板 Twitter 搜索使用 jQuery 的模板来定义用户界面的应用程序内的各个页面。
  • JS 挖空:挖空是一个模型-视图-ViewModel (MVVM) 的框架,构建 ViewModels,并使他们与视图同步 Silverlight 开发人员熟悉的方式很容易。 它是这种相似性,导致我选择挖空,而许多其它合适 JavaScript UI 框架。

我不会在这篇文章中详细报道挖空。 如果你有兴趣了解更多有关这一框架,我推荐阅读约翰爸爸最近一篇文章,挖"变得开始与空"(msdn.microsoft.com/magazine/hh781029)。 如果您不熟悉的 MVVM 模式 (有你一直躲在哪里呢?),我建议这精彩的文章,Josh 史密斯:"WPF 应用程序与模型-视图-ViewModel 设计模式"(msdn.microsoft.com/magazine/dd419663)。

与 Visual Studio 的 JavaScript 应用程序开发

前深入应用程序的详细信息,我想说关于 JavaScript 应用程序开发的几件事。 JavaScript 开发人员所面临的挑战之一就是语言的动态性质。 使用 JavaScript 不被受到一个刚性类型系统 ; 对象可以动态地生成。 这给的 JavaScript 编辑器和 Ide 的开发人员带来了挑战。 使用强类型语言如 C# 和 Java,类型信息可用于提供增强的代码导航、 重构和智能感知。 另一方面,使用 JavaScript,类型信息的缺乏意味着 IDE 通常提供了少得多的开发人员艾滋病。

幸运的是,事情最近有所改善,与 Visual Studio 2010 pseudo-execution JavaScript 代码的执行,以确定每个对象,"形状"允许它提供 JavaScript 智能感知。 为了充分利用智能感知支持,我们有几个"提示"中的"参考"形式提供 IDE,告诉 IDE 要在其 pseudo-execution 中包含的文件。 演示项目中,所有文件都开始时告诉 IDE 包含 intellisense.js 文件的参考注释。 此文件的内容是只需确保在 IDE 中包括所有重要应用 JavaScript 文件跨应用程序,提供质量智能感知支持,如下所示的引用的列表:

/// Ensure IntelliSense includes all the files from this project.
///
/// <reference path="app.js" />
/// <reference path="viewModel/ApplicationViewModel.js" />
/// <reference path="viewModel/SearchResultsViewModel.js" />
/// <reference path="viewModel/TweetViewModel.js" />
/// <reference path="viewModel/TwitterSearchViewModel.js" />
/// <reference path="lib/jquery-1.6.4.js" />
/// <reference path="lib/cordova-1.5.0.js" />
/// <reference path="lib/knockout-1.2.1.js" />

JavaScript 是放松和宽容的语言,功能如值胁迫和半­结肠插入使它易于使用脚本的环境中。 然而,这些相同的功能往往成为一个问题管理大量的代码时。 出于这一原因,我强烈建议使用 JSLint,适用一组更严格的编码标准,JavaScript 的工具。 受欢迎的 Visual Studio 扩展添加 JSLint 支持 (jslint4vs2010.codeplex.com),报告错误控制台内不起毛的软错误。 已经用于 Twitter 搜索应用程序的 JSLint (和我做过几乎所有其他 JavaScript 项目)。

您可能会注意到的每个项目中的 JavaScript 文件开头的"全局变量"注释。 JSLint 可以帮助防止"泄漏"到全球范围的意外遗漏的 var 关键字的变量。 "全局变量"评论为 JSLint 提供正式定义,占据全球范围变量被允许。

MVVM 应用程序结构

Twitter 搜索应用程序从手机的浏览器控件,看是一个单页面的应用程序。 相反,从用户的角度看,它有多个页面,在看到图 5。 为了支持这一点,挖空 ViewModel 构建包含堆栈的 ViewModel 实例,每一个代表在应用程序中的页。 在用户定位到新的一页,相应的 ViewModel 将被添加到此堆栈,而且当用户导航回,最上面的 ViewModel 弹出堆栈的 (请参见图 6)。

图 6 挖空 ApplicationViewModel

/// <reference path="..//intellisense.js" />
/*globals ko*/
function ApplicationViewModel() {
  /// <summary>
  /// The ViewModel that manages the ViewModel back-stack.
/// </summary>
  // --- properties
  this.viewModelBackStack = ko.observableArray();
  // --- functions
  this.
navigateTo = function (viewModel) {
    this.viewModelBackStack.push(viewModel);
  };
  this.back = function () {
    this.viewModelBackStack.pop();
  };
  this.templateSelector = function (viewModel) {
    return viewModel.template;
  }
}

当应用程序启动时,ApplicationViewModel 的实例创建和绑定到使用挖空的 UI:

document.addEventListener("deviceready", initializeViewModel, false);
var application;
function initializeViewModel() {
  application = new ApplicationViewModel();
  ko.applyBindings(application);
}

用户界面本身是很简单,使用挖空模板绑定来呈现 ViewModel 堆栈的 div 元素组成:

<body>
  <h1>Cordova Twitter Search</h1>
  <div class="app"
    data-bind="template: {name: templateSelector,
                          foreach: viewModelBackStack}">
  </div>
</body>

挖空模板绑定工作以类似的方式向 Silverlight ItemsControl,它将绑定到 ViewModel 实例的数组,并负责生成通过模板的每个视图。 在此情况下,templateSelector 函数 ApplicationViewModel 上调用,以确定命名的模板的每个 ViewModel。

如果运行此应用程序时,你会发现其实并不做任何事情 — — 这就是因为没有任何 ViewModels 来表示应用程序的页 !

TwitterSearchViewModel

我将介绍第一 ViewModel,TwitterSearchViewModel,它表示应用程序的第一页。 此 ViewModel 公开几个简单可观察到支持的属性用户界面,即搜索术语,它绑定到用户输入字段和 isSearching,这是将禁用搜索按钮时,Twitter Api 正在查询通过 HTTP 的布尔观测值。 它还公开相同的方式会将 ICommand 绑定到内 Silverlight 按钮绑定到搜索按钮,在很大程度的搜索功能 (请参阅图 7)。

图 7 TwitterSearchViewModel

/// <reference path="..//intellisense.js" />
/*globals $ application ko localStorage SearchResultsViewModel TweetViewModel*/
function TwitterSearchViewModel() {
  /// <summary>
  /// A ViewModel for searching Twitter for a given term.
/// </summary>
  // --- properties
  this.template = "twitterSearchView";
  this.isSearching = ko.observable(false);
  this.searchTerm = ko.observable("");
  // --- public functions
  this.search = function () {
    /// <summary>
    /// Searches Twitter for the current search term.
/// </summary>
    // implementation detailed later in this article ...
};
}

ViewModel 的模板属性的名称与此 ViewModel 相关联的视图。 此视图被描述为一个 jQuery 模板 index.html 文件中:

<script type=text/x-jquery-tmpl" charset="utf-8" id="twitterSearchView" 
  <div>
    <form data-bind="submit: search">
      <input type="text"
        data-bind="value: searchTerm, valueUpdate: 'afterkeydown'" />
      <button type="submit"
        data-bind="enable: searchTerm().length > 0 &&
          isSearching() == false">Go</button> 
    </form>     
  </div>
</script>

如果您将 TwitterSearchViewModel 的实例添加到应用程序 ViewModel 堆栈,现在应用程序显示第一页,如图所示,在图 8

The TwitterSearchViewModel Rendered via the twitterSearchView Template
图 8 的 TwitterSearchViewModel 呈现,通过 twitterSearchView 模板

使用 CSS 创建 UI 地铁

Windows Phone OS 最显著的特征之一是地铁的设计语言,指导手机的外观和感觉的所有方面。 这种设计语言,使优先 chrome 于内容,不只是赏心悦目,也是实用的提供高度可阅接口上小的手机的外形。

当前的用户界面,如图所示,在图 8,使用标准的浏览器样式并因此不是很赏心悦目 ! 已经有几个既定的框架,用于创建使用 HTML 和 CSS,如移动 jQuery 的好看移动 Ui (jquerymobile.com)。 目前这些框架往往集中在模仿 iOS 的外观和感觉。 Windows Phone 科尔多瓦应用可以称为使用 jQuery 移动,虽然因为这根本就不"符合"OS 的整体外观可能会面对一些用户排斥反应。

幸运的是,无铬是很容易复制使用 HTML 和 CSS 的地铁主题。 事实上,Windows 8 将 HTML 视为一个一流的公民,允许您使用 Windows 运行时 Api 的 HTML5 地铁应用程序开发。

通过引入正确的字体、 字体大小和颜色,通过一些简单的 CSS (示图 9),如中所示,您可以创建用户界面的严格遵循地铁主题中, 图 10

图 9 代码,请按照地铁主题

body
{
  background: #000 none repeat scroll 0 0;
  color: #ccc;
  font-family: Segoe WP, sans-serif;
}
h1
{
  font-weight: normal;
  font-size: 42.667px; /* PhoneFontSizeExtraLarge */
}
button
{
  background: black;
  color: white;
  border-color: white;
  border-style: solid;
  padding: 4px 10px;
  border-width: 3px; /* PhoneBorderThickness */
  font-size: 25.333px; /* PhoneFontSizeMediumLarge */
}
input[type="text"]
{
  width: 150px;
  height: 34px;
  padding: 4px;
}

The Twitter Search Application with a Metro CSS Style Applied
图 10 Twitter 搜索应用程序与地铁的 CSS 样式应用

一个最终方面有点儿这是 HTML5 的应用程序,而不是本机的一个例子是用户可以仍然"捏"用户界面,使它放大的赠品。 这可以通过将下面的 meta 属性添加到 index.html 页面部分解决:

<meta name="viewport" content="user-scalable=no" />

这将通知浏览器不允许用户规模呈现的内容。 不幸的是,这通过 Windows Phone 浏览器实现的方式使用户可以缩放内容,但将捕捉回原规模互动结束时。 这个看起来非常好 !

我发现,通过检查 WebBrowser 控件的可视化树,是可能的处理程序附加到操纵事件,并禁止冒泡到本机的 TileHost 呈现 flash 内容。 我发表的一个简短的博客 (bit.ly/vU2o1q),其中包括一个简单的实用程序类,达致这个目标。 但是,应该使用此谨慎,因为这取决于 WebBrowser 控件,这可能会改变在将来版本的 Windows Phone 操作系统的内部结构。

Twitter 搜索

如果你看更为详细地 TwitterSearchViewModel 搜索功能,它会查询通过 jQuery"ajax"函数,它返回 JSONP 响应的 Twitter Api。 TweetViewModel 实例从每个返回的推文的构造和这些被用来构建一个 SearchResultsViewModel 实例 (请参见图 11)。

图 11 TwitterSearchViewModel 搜索功能

this.search = function () {
  /// <summary>
  /// Searches Twitter for the current search term.
/// </summary>
  this.isSearching(true);
  var url = "http://search.twitter.com/search.json?q=" +
    encodeURIComponent(that.searchTerm());
  var that = this;
  $.ajax({
    dataType: "jsonp",
    url: url,
    success: function (response) {
      // Create an array to hold the results.
var tweetViewModels = [];
      // Add the new items.
$.each(response.results, function () {
        var tweet = new TweetViewModel(this);
        tweetViewModels.push(tweet);
      });
      // Navigate to the results ViewModel.
application.
navigateTo(new SearchResultsViewModel(tweetViewModels));
      that.isSearching(false);
    }
  });
};

SearchResultsViewModel 只是包含的推文的列表:

/// <reference path="..//intellisense.js" />
/*globals ko*/
function SearchResultsViewModel(tweetViewModels) {
  /// <summary>
  /// A ViewModel that renders the results of a twitter search.
/// </summary>
  /// <param name="tweetViewModels">An array of TweetViewModel instances</param>
  // --- properties
  this.template = "searchResultsView";
  this.tweets = ko.observableArray(tweetViewModels);
}

TweetViewModel 公开个别的 tweet 和导航到个别的 tweet 视图中,选择函数的属性,如中所示和图 12

图 12 TweetViewModel

/// <reference path="..//intellisense.js" />
/*globals application*/
function TweetViewModel(tweet) {
  /// <summary>
  /// A ViewModel that represents a single tweet
  /// </summary>
  /// <param name="tweet">A tweet as returned by the twitter search API</param>
  // --- properties
  this.template = "tweetDetailView";
  this.author = tweet.from_user;
  this.text = tweet.text;
  this.id = tweet.id;
  this.time = tweet.created_at;
  this.thumbnail = tweet.profile_image_url;
  // --- public functions
  this.select = function () {
    /// <summary>
    /// Selects this tweet, causing the application to navigate to a tweet-view.
/// </summary>
    application.
navigateTo(this);
  };
}

再次,描述这些 ViewModels 的每个视图的模板添加到 index.html 文件,如图所示,在图 13

图 13 index.html 文件添加模板

<script type=text/x-jquery-tmpl" charset="utf-8" id="searchResultsView">
  <div>
    <ul data-bind="template: {name: 'tweetView',
                              foreach: tweets}"> </ul>
  </div>
</script>
<script type="text/x-jquery-tmpl" charset="utf-8" id="tweetView">
  <li class="tweet"
      data-bind="click: select">
    <div class="thumbnailColumn">
      <img data-bind="attr: {src: thumbnail}"
                             class="thumbnail"/>
    </div>
    <div class="detailsColumn">
      <div class="author"
           data-bind="text: author"/>
      <div class="text"
           data-bind="text: text"/>
      <div class="time"
           data-bind="text: time"/>
    </div>
  </li>
</script>

使用此代码中的地方,当用户点击"转"的按钮,以搜索 Twitter,新的 SearchResultsViewModel 被添加到 ViewModel 堆栈。 这将自动导致正在呈现在"应用程序"专区内的 searchResultsView 模板 但是,由于 ViewModel 堆栈通过 foreach 模板绑定呈现出来,这不会隐藏 twitterSearchView 模板实例 ; 而他们就会堆积另一个上面。 这可以通过几个简单的 CSS 规则添加解决:

.app>div
{
  display: none;
}
.app>*:last-child
{
  display: block;
}

第一个选择器隐藏 div 标记与应用程序的类,而第二个选择器,具有更高的优先级,确保显示的最后一个子级的所有即时的儿童。

这些位置中的 CSS 规则,Twitter 搜索应用程序是完全功能和通航。

管理 Back 堆栈

与当前 Twitter 搜索应用程序,您可以从搜索导航到个别的 tweet,结果页,但如果你打手机后退按钮立即退出应用程序。 这是因为应用程序导航出现完全在一个浏览器控件内 — — 因此,Silverlight 框架的角度来看,从应用程序具有单个页面。 这不仅会导致糟糕的用户体验,它几乎肯定会被拒绝,如果提交到 Windows Phone 市场上的应用程序中。

幸运的是,这个问题的解决方案是简单的。 ApplicationViewModel 包含一个 ViewModel 实例的堆栈。 如果此堆栈中有多个 ViewModel 实例,您需要处理硬件后按下按钮和关闭此堆栈的最顶层 ViewModel 流行。 否则,您可以允许 Silverlight 退出应用程序框架。

为了提供支持,backButtonRequired 依赖观测值添加到 ViewModel:

function ApplicationViewModel() {
  // --- properties
  this.viewModelBackStack = ko.observableArray();
  this.backButtonRequired = ko.dependentObservable(function () {   
    return this.viewModelBackStack().length > 1;
  }, this);
  // --- functions
  // ...
}

ViewModel 初始化时,您可以处理此观测值的更改和订阅科尔多瓦用品的 backbutton 事件。 当触发该事件时,请调用背上的 ApplicationViewModel,弹出堆栈的最顶层 ViewModel 函数。 挖空模板绑定照顾从用户界面中删除 ViewModel 关联的视图和 CSS 样式设置确保是可见的认为现在是最顶层 (请参见图 14)。

图 14 处理后按下按钮

function initializeViewModel() {
  application = new ApplicationViewModel();
  ko.applyBindings(application);
  // Handle the back button.
application.backButtonRequired.subscribe(function (backButtonRequired) {
    if (backButtonRequired) {
      document.addEventListener("backbutton", onBackButton, false);
    } else {
      document.removeEventListener("backbutton", onBackButton, false);
    }
  });
  var viewModel = new TwitterSearchViewModel();
  application.
navigateTo(viewModel);
}
function onBackButton() {
  application.back();
}

因为通过科尔多瓦中的代码提供了 backbutton 事件,则图 14 会工作得很好如果执行应用程序使用不同的手机操作系统 (只要手机本身具有硬件后退按钮)。

状态持久性

我们会将最后的一个功能添加到 Twitter 搜索应用程序:当搜索成功返回时,搜索词添加到最近的搜索列表 (请参见图 15)。

图 15 到最近的搜索列表中添加一个搜索词

function TwitterSearchViewModel() {
  /// <summary>
  /// A ViewModel for searching Twitter for a given term.
/// </summary>
  // --- properties
  // ...
some properties omitted for clarity ...
this.recentSearches = ko.observableArray();
  // --- functions
  // ...
some functions omitted for clarity ...
this.loadState = function () {
    /// <summary>
    /// Loads the persisted ViewModel state from local storage.
/// </summary>
    var state = localStorage.getItem("state");
    if (typeof (state) === 'string') {
      $.each(state.split(","), function (index, item) {
        if (item.trim() !== "") {
          that.recentSearches.push(item);
        }
      });
    }
  };
  function saveState() {
    /// <summary>
    /// Saves the ViewModel state to local storage.
/// </summary>
    localStorage.setItem("state", that.recentSearches().toString());
  }
  function addSearchTermToRecentSearches() {
    /// <summary>
    /// Adds the current search term to the search history.
/// </summary>
    that.recentSearches.unshift(that.searchTerm());
    saveState();
  }
}

AddSearchTermToRecentSearches 函数采用挖空方便的功能,unshift,其中将项添加到数组的开始。 添加最近的搜索,使用 HTML5 本地存储存储状态。 在此情况下数组的状态被转换为通过 toString 函数,以逗号分隔的列表,并转换回通过拆分。 更复杂的 ViewModel 很可能会 JSON 格式保存多个属性值。

有趣的是,虽然 Windows Phone 浏览器不支持本地存储,此函数时关闭浏览器呈现页从独立存储。 为了使较早的代码工作,科尔多瓦团队不得不写的本地存储保存的状态,在手机的独立存储内的 Api 的"农心"执行。

Twitter 搜索应用程序要这最后的更改,现在是完全正常。

可移植性证明:在 iPhone 上运行

正如您所看到的科尔多瓦框架使创建基于 HTML5 的应用程序的 Windows Phone。 它也是可以模拟使用简单的 HTML5 和 CSS 技术,如挖空框架允许您正确地组织代码时的本机地铁外观和感觉。

这篇文章侧重于为 Windows Phone,创建应用程序,但 Twitter 搜索应用程序是便携式和应在 iPhone 或未经修改的 Android 手机上运行。 但地铁样式应用适合这些手机吗?

作为最后的这种做法的多功能演示,我创建了 iOS 版本的 Twitter 搜索应用程序,使用 jQuery 移动来模仿本机的外观和感觉。 这使得大 ; 使用 MVVM 的模式,在这只查看需要改变 — ViewModel 的逻辑是完全相同的。 使用基于云计算的生成服务得以对创建 iOS"ipa"包和 iPhone,全部从 Windows 机器上安装它。 你可以看到两个应用程序在运行中并排图 16

Twitter Search Running on an iPhone and a Windows Phone Device
IPhone 和 Windows Phone 设备上图 16 Twitter 搜索较大的运行

本文附带的 iOS 和 Windows Phone 版本的应用程序的完整源代码。

Colin Eberhardt 是技术设计师斯科特逻辑有限公司 和铅建筑师在 Visiblox (visiblox.com),其中提供图表控件,微软的范围。NET 框架技术。您可以按照他在 Twitter 上 twitter.com/ColinEberhardt

多亏了以下技术专家,检讨这篇文章: Olivier Bloch,Glen GordonJesse MacFadyen