当前位置: 首页 > 编程日记 > 正文

[WP]使用ApacheCordova开发HTML5-WindowsPhone应用程序

下载代码示例

这篇文章介绍 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


图 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


图 2 为 Windows Phone 科尔多瓦包括 Visual Studio 模板

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


图 3 运行模拟器上的科尔多瓦模板应用程序

Windows Phone 科尔多瓦应用解剖

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


图 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 文件,您可以看到它会等待直到设备准备好之前更新用户界面:

  1. <script type="text/javascript">
  2. document.addEventListener("deviceready",onDeviceReady,false);
  3. function onDeviceReady()
  4. {
  5. document.getElementById("welcomeMsg").innerHTML
  6. += "Cordova is ready!
  7. version=" + window.device.cordova;
  8. console.log(
  9. "onDeviceReady.
  10. You should see this " +
  11. "message in Visual Studio's output window.");
  12. }
  13. </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


图 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 文件跨应用程序,提供质量智能感知支持,如下所示的引用的列表:

  1. /// Ensure IntelliSense includes all the files from this project.
  2. ///
  3. /// <reference path="app.js" />
  4. /// <reference path="viewModel/ApplicationViewModel.js" />
  5. /// <reference path="viewModel/SearchResultsViewModel.js" />
  6. /// <reference path="viewModel/TweetViewModel.js" />
  7. /// <reference path="viewModel/TwitterSearchViewModel.js" />
  8. /// <reference path="lib/jquery-1.6.4.js" />
  9. /// <reference path="lib/cordova-1.5.0.js" />
  10. /// <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

  1. /// <reference path="..//intellisense.js" />
  2. /*globals ko*/
  3. function ApplicationViewModel() {
  4. /// <summary>
  5. /// The ViewModel that manages the ViewModel back-stack.
  6. /// </summary>
  7. // --- properties
  8. this.viewModelBackStack = ko.observableArray();
  9. // --- functions
  10. this.
  11. navigateTo = function (viewModel) {
  12. this.viewModelBackStack.push(viewModel);
  13. };
  14. this.back = function () {
  15. this.viewModelBackStack.pop();
  16. };
  17. this.templateSelector = function (viewModel) {
  18. return viewModel.template;
  19. }
  20. }

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

  1. document.addEventListener("deviceready", initializeViewModel, false);
  2. var application;
  3. function initializeViewModel() {
  4. application = new ApplicationViewModel();
  5. ko.applyBindings(application);
  6. }

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

  1. <body>
  2. <h1>Cordova Twitter Search</h1>
  3. <div class="app"
  4. data-bind
  5. ="template: {name: templateSelector,
  6. foreach: viewModelBackStack}"

>

  1. </div>
  2. </body>

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

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

TwitterSearchViewModel

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

图 7 TwitterSearchViewModel

  1. /// <reference path="..//intellisense.js" />
  2. /*globals $ application ko localStorage SearchResultsViewModel TweetViewModel*/
  3. function TwitterSearchViewModel() {
  4. /// <summary>
  5. /// A ViewModel for searching Twitter for a given term.
  6. /// </summary>
  7. // --- properties
  8. this.template = "twitterSearchView";
  9. this.isSearching = ko.observable(false);
  10. this.searchTerm = ko.observable("");
  11. // --- public functions
  12. this.search = function () {
  13. /// <summary>
  14. /// Searches Twitter for the current search term.
  15. /// </summary>
  16. // implementation detailed later in this article ...
  17. };
  18. }

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

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

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


图 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 代码,请按照地铁主题

  1. body
  2. {
  3. background: #000 none repeat scroll 0 0;
  4. color: #ccc;
  5. font-family: Segoe WP, sans-serif;
  6. }
  7. h1
  8. {
  9. font-weight: normal;
  10. font-size: 42.667px; /* PhoneFontSizeExtraLarge */
  11. }
  12. button
  13. {
  14. background: black;
  15. color: white;
  16. border-color: white;
  17. border-style: solid;
  18. padding: 4px 10px;
  19. border-width: 3px; /* PhoneBorderThickness */
  20. font-size: 25.333px; /* PhoneFontSizeMediumLarge */
  21. }
  22. input[type="text"]
  23. {
  24. width: 150px;
  25. height: 34px;
  26. padding: 4px;
  27. }


图 10 Twitter 搜索应用程序与地铁的 CSS 样式应用

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

  1. <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 搜索功能

  1. this.search = function () {
  2. /// <summary>
  3. /// Searches Twitter for the current search term.
  4. /// </summary>
  5. this.isSearching(true);
  6. var url = "http://search.twitter.com/search.json?q=" +
  7. encodeURIComponent(that.searchTerm());
  8. var that = this;
  9. $.ajax({
  10. dataType: "jsonp",
  11. url: url,
  12. success: function (response) {
  13. // Create an array to hold the results.
  14. var tweetViewModels = [];
  15. // Add the new items.
  16. $.each(response.results, function () {
  17. var tweet = new TweetViewModel(this);
  18. tweetViewModels.push(tweet);
  19. });
  20. // Navigate to the results ViewModel.
  21. application.
  22. navigateTo(new SearchResultsViewModel(tweetViewModels));
  23. that.isSearching(false);
  24. }
  25. });
  26. };

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

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

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

图 12 TweetViewModel

  1. /// <reference path="..//intellisense.js" />
  2. /*globals application*/
  3. function TweetViewModel(tweet) {
  4. /// <summary>
  5. /// A ViewModel that represents a single tweet
  6. /// </summary>
  7. /// <param name="tweet">A tweet as returned by the twitter search API</param>
  8. // --- properties
  9. this.template = "tweetDetailView";
  10. this.author = tweet.from_user;
  11. this.text = tweet.text;
  12. this.id = tweet.id;
  13. this.time = tweet.created_at;
  14. this.thumbnail = tweet.profile_image_url;
  15. // --- public functions
  16. this.select = function () {
  17. /// <summary>
  18. /// Selects this tweet, causing the application to navigate to a tweet-view.
  19. /// </summary>
  20. application.
  21. navigateTo(this);
  22. };
  23. }

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

图 13 index.html 文件添加模板

  1. <script type=text/x-jquery-tmpl" charset="utf-8" id="searchResultsView">
  2. <div>
  3. <ul data-bind="template: {name: 'tweetView',
  4. foreach: tweets}"> </ul>
  5. </div>
  6. </script>
  7. <script type="text/x-jquery-tmpl" charset="utf-8" id="tweetView">
  8. <li class="tweet"
  9. data-bind="click: select">
  10. <div class="thumbnailColumn">
  11. <img data-bind="attr: {src: thumbnail}"
  12. class="thumbnail"/>
  13. </div>
  14. <div class="detailsColumn">
  15. <div class="author"
  16. data-bind="text: author"/>
  17. <div class="text"
  18. data-bind="text: text"/>
  19. <div class="time"
  20. data-bind="text: time"/>
  21. </div>
  22. </li>
  23. </script>

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

  1. .app>div
  2. {
  3. display: none;
  4. }
  5. .app>*:last-child
  6. {
  7. display: block;
  8. }

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

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

管理 Back 堆栈

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

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

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

  1. function ApplicationViewModel() {
  2. // --- properties
  3. this.viewModelBackStack = ko.observableArray();
  4. this.backButtonRequired = ko.dependentObservable(function () {
  5. return this.viewModelBackStack().length > 1;
  6. }, this);
  7. // --- functions
  8. // ...
  9. }

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

图 14 处理后按下按钮

  1. function initializeViewModel() {
  2. application = new ApplicationViewModel();
  3. ko.applyBindings(application);
  4. // Handle the back button.
  5. application.backButtonRequired.subscribe(function (backButtonRequired) {
  6. if (backButtonRequired) {
  7. document.addEventListener("backbutton", onBackButton, false);
  8. } else {
  9. document.removeEventListener("backbutton", onBackButton, false);
  10. }
  11. });
  12. var viewModel = new TwitterSearchViewModel();
  13. application.
  14. navigateTo(viewModel);
  15. }
  16. function onBackButton() {
  17. application.back();
  18. }

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

状态持久性

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

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

  1. function TwitterSearchViewModel() {
  2. /// <summary>
  3. /// A ViewModel for searching Twitter for a given term.
  4. /// </summary>
  5. // --- properties
  6. // ...
  7. some properties omitted for clarity ...
  8. this.recentSearches = ko.observableArray();
  9. // --- functions
  10. // ...
  11. some functions omitted for clarity ...
  12. this.loadState = function () {
  13. /// <summary>
  14. /// Loads the persisted ViewModel state from local storage.
  15. /// </summary>
  16. var state = localStorage.getItem("state");
  17. if (typeof (state) === 'string') {
  18. $.each(state.split(","), function (index, item) {
  19. if (item.trim() !== "") {
  20. that.recentSearches.push(item);
  21. }
  22. });
  23. }
  24. };
  25. function saveState() {
  26. /// <summary>
  27. /// Saves the ViewModel state to local storage.
  28. /// </summary>
  29. localStorage.setItem("state", that.recentSearches().toString());
  30. }
  31. function addSearchTermToRecentSearches() {
  32. /// <summary>
  33. /// Adds the current search term to the search history.
  34. /// </summary>
  35. that.recentSearches.unshift(that.searchTerm());
  36. saveState();
  37. }
  38. }

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


IPhone 和 Windows Phone 设备上图 16 Twitter 搜索较大的运行

原文来自:http://msdn.microsoft.com/zh-cn/magazine/hh975345.aspx

转载于:https://www.cnblogs.com/webapplee/p/3767808.html

相关文章:

linux 不能运行程序代码,linux-无法在Ubuntu上运行我自己的OpenGL 3程序

我正在尝试OpenGL 2.x和3.x教程.程序进行编译和链接,然后在看似无害的行上进行段错误处理,例如glGenBuffers (1, &m_buffer);我的main()以glewInit和glutInit开头. OpenGL 1程序可以编译并正常运行,这似乎是由glew包装的新功能.一个教程说,在尝试任何其他操作之前,我应该先…

Cocos2d-x Eclipse下程序运行产生错误Effect initCheck() returned -1

错误大致显示如下信息&#xff1a;04-14 07:39:18.325: E/AudioEffect(20584): set(): AudioFlinger could not create effect, status: -104-14 07:39:18.325: E/libOpenSLES(20584): Effect initCheck() returned -104-14 07:39:18.325: E/libOpenSLES(20584): Environmental…

H2:开源内存数据库引擎

本资源由 伯乐在线 - 刘立华 整理H2是一个开源的内存数据库。Java编写、快速、小巧&#xff08;1.5MB jar包&#xff09;还提供了Web控制台管理数据库内容。 主要功能 非常快速的数据库引擎。开源。Java编写。支持标准SQL、JDBC API。支持嵌入式模式、服务器模式和集群。强大的…

递归/回溯:Combination Sum II数组之和

问题如下&#xff1a; 已知一组数(其中有重复元素)&#xff0c;求这组数可以组成的所有子集中&#xff0c;子 集中的各个元素和为整数target的子集&#xff0c;结果中无重复的子集。 例如: nums[] [10, 1, 2, 7, 6, 1, 5]&#xff0c; target 8 结果为: [[1, 7], [1, 2, 5], …

如何在SharePoint2010中添加Deep Zoom Image

如何在SharePoint2010中添加Deep Zoom Image 应用范围 SharePoint 2010 Foundation&#xff1b;SharePoint 2010 Standard&#xff1b;SharePoint 2010 Enterprise所需材料 1. SeaDragon Ajax Viewer Web部件&#xff08;点击此处下载&#xff09;2. Deep Zoom Image Composer&…

linux 读取磁盘扇区,linux 下检查硬盘坏道/扇区

文章摘自&#xff1a;Linux检测硬盘坏道Linux检测硬盘坏道badblocks功能说明&#xff1a;检查磁盘装置中损坏的区块。语法&#xff1a;badblocks [-svw][-b ][-o ][磁盘装置][磁盘区块数][启始区块]补充说明&#xff1a;执行指令时须指定所要检查的磁盘装置&#xff0c;及此装置…

Pjax是什么以及为什么推荐大家用

什么是pjax? 现在很多网站( facebook, twitter) 都支持这样的一种浏览方式&#xff0c; 当你点击一个站内的链接的时候&#xff0c; 不是做页面跳转&#xff0c; 而是只是站内页面刷新。 这样的用户体验&#xff0c; 比起整个页面都闪一下来说&#xff0c; 好很多。 其中有一…

Scrapy框架CrawlSpider类爬虫实例

CrawlSpider类爬虫中&#xff1a; rules用于定义提取URl地址规则&#xff0c;元祖数据有顺序 #LinkExtractor 连接提取器&#xff0c;提取url地址 #callback 提取出来的url地址的response会交给callback处理 #follow 当前url地址的响应是否重新经过rules进行提取url地址 cf.py具…

递归/回溯:Generate Parentheses生成合法括号

已知n组括号&#xff0c;开发一个程序&#xff0c;生成这n组括号所有的合法的组合可能。 例如:n 3 结果为: ["((()))", “(()())”, “(())()”, “()(())”, “()()()”] 首先思考如何生成所有的括号组合的可能性&#xff0c;即例如2组括号&#xff0c;总共4个符号…

利用“哨兵”“实现双链表

利用“哨兵”“实现双链表 下面的代码用一个”哨兵“实现双链表&#xff0c;感觉很简洁&#xff0c;中间也有点绕&#xff0c;暂时实现&#xff0c;供学习之用 static Node list_handle {&list_handle,&list_handle, };bool addNode(Node* node) {if (node NULL){re…

suse linux显示乱码,open suse11.4中文乱码问题

winland0704 于 2011-04-07 00:56:10发表:不是乱码&#xff0c;而是字符编码标准不一样。windows的文本使用GBK&#xff0c;国标码。Linux使用Unicode编码。解决参看&#xff1a;hi.baidu.com/winland0704/blog/item/c58008512cc843c9b645aef1.html四、其他的一些问题3、文本编…

软件破解系列之OD中断方法

OD中断方法浅探 Ollydbg是一个新的32位的汇编层调试软件。适应于windows98、me、2000、xp和2003操作系统。由于他具有图形窗口界面&#xff0c;所以操作方便、直观&#xff0c;是cracker的好工具。 由于Ollydbg没有了TRW2000的万能断点&#xff0c;所以许多的新手感觉到用Ollyd…

MongoDB系列:二、MongoDB常用操作练习

最近在自学MongoDB&#xff0c;在此记录一下&#xff0c;当做学习笔记了&#xff08;不断更新中&#xff09;&#xff01;&#xff01; 一、背景 MongoDB 是一个基于分布式文件存储的数据库。由 C 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。它是一个介于关…

递归/回溯:八皇后问题N-Queens

N皇后问题是计算机科学中最为经典的问题之一&#xff0c;该问题可追溯到1848年&#xff0c;由国 际西洋棋棋手马克斯贝瑟尔于提出了8皇后问题。 将N个皇后放摆放在N*N的棋盘中&#xff0c;互相不可攻击&#xff0c;有多少种摆放方式&#xff0c;每种摆 放方式具体是怎样的? 8…

KS103超声波测距模块

max232&#xff1a;电平转换芯片&#xff0c;将电脑的RS-232标准串口&#xff08;高12V&#xff0c;低-12V&#xff09;转换为&#xff08;高5V&#xff0c;低0V&#xff09;。 电脑串口&#xff08;RS -232&#xff09; > 单片机串口&#xff08;TTL串口&#xff09; SIPEX…

linux 硬盘操作,linux常用disk磁盘操作命令

#按照目录大小排序战士最前面15个目录或者文件du -xB M --max-depth2 /var | sort -rn | head -n 15#列出当前所有子目录的文件大小du -h --max-depth1#列出当前文件或者目录最大的10个du -s * | sort -n | tail#按照目录大小从大到小排序du -b --max-depth 1 | sort -nr | per…

在Spring中采用声明式方法对Hibernate和JDBC进行统一的事务配置(AOP)

<?xml version"1.0" encoding"UTF-8"?><beans xmlns"http://www.springframework.org/schema/beans" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xmlns:aop"http://www.springframework.…

Leetcode 213.大家劫舍II

打家劫舍II 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈&#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的。同时&#xff0c;相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房…

替代Druid,HakariCP 为什么这么快?

这次源码探究,真的感觉看到了无数个小细节,无数个小优化,积少成多。平时开发过程中,一些小的细节也一定要“扣”。

递归/分治:归并排序

前言 分治算法: 将一个规模为N的问题分解为K个规模较小的子问题&#xff0c;这些子问题相互独立且与原问题性质相同。求出 子问题的解后进行合并&#xff0c;就可得到原问题的解。 步骤如下: 分解&#xff0c;将要解决的问题划分成若 干规模较小的同类问题;求解&#xff0c;…

Java中volatile 的使用场景有哪些?

volatile是一种轻量级的同步机制,它能保证共享变量的可见性,同时禁止重排序保证了操作的有序性,但是它无法保证原子性。所以使用volatilevolatile。

JDK22 正式发布了 !

Java 22 除了推出了新的增强功能和特性,也获得 Java Management Service (JMS) 的支持,这是一项新的 Oracle 云基础设施远程软件服务(Oracle Cloud Infrastructure, OCI) 原生服务,提供统一的控制台和仪表盘,帮助企业管理本地或云端的 Java 运行时和应用。使包含运行时计算值的字符串更容易表达,简化 Java 程序的开发工作,同时提高将用户提供的值编写成字符串,并将字符串传递给其他系统的程序的安全性。支持开发人员自由地表达构造器的行为。

Jackson 用起来!

你可以创建自定义序列化器和反序列化器以自定义特定字段或类的序列化和反序列化行为。为此,请创建一个实现或接口的类,并在需要自定义的字段或类上使用和注解。@Override// ...其他代码...优势性能优异:Jackson在序列化和反序列化过程中表现出优秀的性能,通常比其他Java JSON库更快。灵活性:通过注解、自定义序列化器/反序列化器等功能,Jackson提供了丰富的配置选项,允许你根据需求灵活地处理JSON数据。易于使用:Jackson的API设计简洁明了,易于学习和使用。

Swift中的问号?和感叹号!

Swift语言使用var定义变量&#xff0c;但和别的语言不同&#xff0c;Swift里不会自动给变量赋初始值&#xff0c;也就是说变量不会有默认值&#xff0c;所以要求使用变量之前必须要对其初始化。如果在使用变量之前不进行初始化就会报错&#xff1a; var stringValue : String …

拜托!别再滥用 ! = null 判空了!!

另外,也许受此习惯影响,他们总潜意识地认为,所有的返回都是不可信任的,为了保护自己程序,就加了大量的判空。如果你养成习惯,都是这样写代码(返回空collections而不返回null),你调用自己写的方法时,就能大胆地忽略判空)这种情况下,null是个”看上去“合理的值,例如,我查询数据库,某个查询条件下,就是没有对应值,此时null算是表达了“空”的概念。最终,项目中会存在大量判空代码,多么丑陋繁冗!,而不要返回null,这样调用侧就能大胆地处理这个返回,例如调用侧拿到返回后,可以直接。

ffmpeg java linux水印,Linux环境用FFmpeg给视频加水印详细步骤

FFmpeg给视频添加水印&#xff0c;根据官方文档的介绍可以知道FFmpeg在编译安装的时候还需要加 –enable-libfreetype、–enable-libfontconfig、 --enable-libfribidi 这几个参数&#xff0c;而这几个组件又需要从外面编译安装&#xff0c;我看很多博主直接用FFmpeg命令加水印…

red hat DHCP服务器配置

[ 基本操作 ] rpm –q dhcp / rpm -ql grep dhcp [ 查询DHCP ] yum –y install dhcp dhcp -devel service dhcpd start [ 启动 ] service dhcpd status [ 查看DHCP状态 ] chkconfig – level 3 5 dhcpd on [ 改变启动级别为3 5 自动启动服务 ] service ne…

axios解决调用后端接口跨域问题

vue-cli通过是本地代理的方式解决接口跨域问题的。但是在vue-cli的默认项目配置中这个代理是没有配置的&#xff0c;如果现在项目中使用&#xff0c;必须手动配置config/index.js文件 ... proxyTable: {/api: { //将www.exaple.com印射为/apistarget: https://www.example.c…

递归/归并:count of smaller numbers求逆序数

已知数组nums&#xff0c;求新数组count&#xff0c;count[i]代表了在nums[i]右侧且比 nums[i]小的元素个数。 例如: nums [5, 2, 6, 1], count [2, 1, 1, 0]; nums [6, 6, 6, 1, 1, 1], count [3, 3, 3, 0, 0, 0]; nums [5, -7, 9, 1, 3, 5, -2, 1], count [5, 0, 5, 1…

远程计划任务管理

有时你需要远程管理或运行一批机器&#xff0c;但是按要求你没有权限或者不能安装客户端&#xff0c;下面的批处理可能帮上你的忙&#xff0c;将下方代码保存为批处理&#xff0c;并创建Clients.txt&#xff0c;存放的是以回车分隔的IP echo off setlocal enabledelayedexpansi…