包括 HTML、CSS 和 JavsScript 的 Web 技术正被 Metro 风格的程序采纳为视窗程序中首类(first-class)的开发技术。比较起来,JavaScript 不像传统 Web 服务器那样部署在一张又一张的页面上,Metro App 是本地安装在客户机器上的。这点很像传统的 Win 程序,但是直接可以使用 JavaScript 访问所在的底层 API,还能和其他程序相沟通。
注意,如果您倾向于 C#, C++, or VB withXAML,开发,请参阅 Buildingyour first Windows Metro style app with C#, C++, or VB。
目标
Hello Win Metro
跟 web 页面那样,得先有一份 HTML 文件去写 Metro App。
<!DOCTYPE html> <html> <head><title>你好Windows Metro styleapps!</title></head> <body><h1>欢迎来到 Windows Metro styleapps</h1></body> </html>
如果把这 HTML 放在浏览器中运行,肯定没啥意思。不用多说,如果在 Metro App 中执行,则又是另外一番天地,当然您的客户,一般不会在乎那究竟是浏览器还是 Metro App。只不过,有明显不同,就是 Metro App 会安装在 Window Store 中,跟其他 Win 程序一样。再者,若说单张 Web 页面,根本算不上叫做完整的程序,哪怕涉及样式、代码、图片资源的那些。现在,Metro App 不但包括这些,而且还提格为标准的应用程序,于是将有元数据和程序资源文件的出现:
用于描述程序本身的清单文件(manifest),包括程序名称、简介、启动页等等。
用于外观的图片文件或者图标文件。
用于Windows Store显示的图标 logo。
用于你程序启动时欢迎屏幕(a splash screen)。
程序清单(manifest)是一份名为 appxmanifest.xml 的 XML 文件。该文件包括了诸如程序名称、程序描述、图片引用等的详细情况,其中一项当属最重要的是指定程序的启动页。Microsoft Visual Studio 11 Express for Windows Developer Preview 可以自动导出程序清单,而还可以帮助你透过 JavaScript 来完成一系列任务,这些任务就是创建、编辑、打包、启动与调试您的 Metro 风格应用程序。
在 VS 中开发Windows Metro Apps
Microsoft Visual Studio 为开发视窗程序的工具,也是开发 Metro式程序的第一个工具。它不但提供了 HTML、CSS、JavaScript、图片编辑,以及用 JavaScript 来编辑程序清单等等此类一般开发任务,还包括整个开发周期的项目管理,涉及到源码管理、整合构建(build)以及部署等的许多过程。有几种 VS 版本的制定,我们这里拿来使用的是免费的 Visual Studio 11 Express for Windows Developer Preview 预览版本,在 Windows Software Development Kit (SDK) for MetroApp 就有。安装一遍后就等于安装好了编译、打包、部署的那些工具。VisualStudio 11 Express for Windows Developer Preview 本身提供若干模板,如下图所示:
最简单的项目模板就是 Blank Application。运行之后生成 Visual Studio 11 Express for WindowsDeveloper Preview Metro style app using JavaScript 项目专属文件(.wwaproj )。
现在打开预设的 default.html 的话,你会发现这几乎全是空的内容,打开 js 目录下的 default.js 也同样如是。明显这里提供的是主干文件,等着你创造些内容添加进去。
欲进行调试,你点击“Debug > StartDebugging”就可以,它提供了开发者所熟悉的几项调试工具:
调试器,打断点、步进和监视 JS 数据和行为。
JS 控制台窗口(JavaScript ConsoleWindow),与JS对象命令行交互的地方。
DOM浏览器窗口,观察 HTML Document Object Model 或者元素样式的地方。
模拟器(Simulator),在开发环境中模拟相关设备的事件。
采用 JavaScript 编写的 MetroApp,除却语法,在访问 Windows 底层平台的时候与其他语言无异。但根据 JavaScript 程序员的某些特性又应该有一些尽量预设的包,可以反复使用的设计,也就是说,Windows 类库针对 JavaScript 特定提供了一组可复用的 JS 和 CSS 文件,以便在此基础上更好地体现 Windows 新特性。VS 模板中已经包含了一系列的 CSS 样式规则表,以便提供划一的 WinApp 的风格感官(look& feel)。最简捷的方式就是通过项目模板文件引入,它会自动包含 WinJS 所需的文件。
Blank Application 项目文件虽说空无一物的,却已包含有一定的样式在内。Metro 风格之所以称“风格”,应该说对样式有一点要求的。样式本身固然不是说要统一一致,因为许多情况下有你需要特定的布局、动作个性化的设计。我们这里就会举一个例子。实际上,尽管所谓 Metro 风格的程序是新鲜事物,但过往的经验仍值得学习研究。这里为大家介绍 Window 项目组里的一位精于此道的开发人员,Raymond Chen。陈先生是一本优秀图书《The Old New Thing》的作者,同时他还是 Weblog 的作者。
陈先生的主要成果在于看到了一般人不容易看到 Win 平台上的缺失之处,或曰美中不足,并且将文字连同示例 Sample 资源积极地发表在他博客上。这样,都是 Win 的程序,我们可以通过这些素材展示新的构造方式。
由此,我们需要在他博文下载数据,才可以清楚哪些地方放置代码。
调用WinJS.Application对象
项目模板生成的 default.html 文件默认加载 WinJS 所需最低要求的 JS 和 CSS 文件:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>RssReader</title> <!-- WinJS references --> <link rel="stylesheet" href="/winjs/css/ui-dark.css" /> <script src="/winjs/js/base.js"></script> <script src="/winjs/js/wwaapp.js"></script> <!-- RssReader references --> <link rel="stylesheet" href="/css/default.css" /> <script src="/js/default.js"></script> </head> <body> </body> </html>加入我们自己的内容:
<body> <h1>The Old New Thing</h1> <div id="downloadStatus"></div> <div id="posts"></div> </body>
- 上面分别是一标题和两个 div 元素用于容器(placeholder)的作用,一个表示 RSS 下载时的状态如何;另一个为我们获取好 RSS 内容将来显示的地方。别忘了,我们要用到陈兄的那些样式文件:
/* default.css */ body { background-color: #fff; color: #000; font-family: Verdana; padding: 8pt; } a:link, a:visited, a:active { color: #700; font-weight: inherit; } h1 { text-transform: none; font-family: inherit; font-size: 22pt; } #posts { width: 99%; height: 100%; overflow: auto; } .postTitle { color: #700; font-size: 1.2em; font-weight: bold; } .postDate { color: #666; font-size: 11pt; } .postContent { font-size: medium; line-height: 18px; }为了使得 MetroApp 与其他应用程序之间整合,Windows 提供了一组程序级别(app-level)的消息事件,均由 WinJS 完备封装。那份 default.js 文件内就订阅了(或登记了)程序的加载事件,程序于是开启时便会执行:
// default.js (function () { 'use strict'; // Uncomment the following line to enable first chanceexceptions. // Debug.enableFirstChanceException(true); WinJS.Application.onmainwindowactivated = function (e) { if (e.detail.kind ===Windows.ApplicationModel.Activation.ActivationKind.launch) { // TODO: 这里写启动代码 } } WinJS.Application.start(); })();首先你必须留意的一件事是,上述代码都是处在一个自动执行的匿名函数中去运行的。这个是一个避免污染全局空间的 JavaScript 实践方法,也是常常被人推荐的技巧。第二请留意
Debug
命名空间下调用的
enableFirstChanceException
方法。取消注释的话就会向VS的调试器报告初期的 JavaScript 异常,确实十分方便的说。
前期工作完毕后,由 WinJS 命名空间下得到的对象,此时此刻,代码就会订阅在程序及其资源(如default.html)都已经加载好了才会触发的事件。这是一个执行初始化绝佳的地方和时刻,待会我们会见到。对于触发任何程序事件,你一定要让程序晓得你已经准备好介绍消息了,也就是要执行方法是怎样。onmainwindowactivated 的事件处理器(event handler)就是我们接着将要下载陈先生博客的绝佳之地。
运用 WinJS.xhr 下载数据
WinJS 命名空间下 xhr 函数提供一系列的可选项,以备下载来自 HTTP 协议的数据,普通文本和 XML 的都可以。xhr 为 XMLHttpRequest 的意思。WinJS 里的 xhr 是一个包装器,可送入许多参数,包括 HTTP 动词(默认 GET)、HTTP 头(默认 none )和获取数据的源地址 URL。
WinJS.Application.onmainwindowactivated = function (e) { if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) { // 开始下载 downloadStatus.innerText = "downloading posts..."; WinJS.xhr({ url: "http://blogs.msdn.com/b/oldnewthing/rss.aspx" }). then(processPosts, downloadError); } }
与 XMLHttpRequest 对象可选择数据同步(synchronously)或异步(asynchronously)通讯的方式不同,WinJs.xhr()只能选择异步方式的通讯,其考量是为了防止同步通信而造成的UI阻塞。异步模式下编码模型,能够帮助你编写更灵敏响应的应用程序。该例子中,我们不知道请求花去多少时间,于是,我们安排一个 div 来作为反馈下载状态 downloadStatus 的 UI 容器。
WinJS 对象下的异步函数称作“允诺 promise”,表示将来发生的结果。Promise 对象暴露了then 函数,即 success 函数、failure 函数和 prgress 函数。调用 xhr() 立刻返回promise 对象,于是我们设定这三个函数的具体情形。
function processPosts(request) { // 清空提示内容 downloadStatus.innerText = ""; // 解析RSS var items = request.responseXML.selectNodes("//item"); if( items.length == 0 ) { downloadStatus.innerText = "下载帖子出错。"; } for( var i = 0, len = items.length; i < len; i++ ) { var item = items[i]; // 向 #posts div 添加数据 var parent = document.createElement("div"); appendDiv(parent, item.selectNodes("title")[0].text, "postTitle"); appendDiv(parent, item.selectNodes("pubDate")[0].text, "postDate"); appendDiv(parent, item.selectNodes("description")[0].text, "postContent"); posts.appendChild(parent); } } function appendDiv(parent, html, className) { var div = document.createElement("div"); div.innerHTML = html; div.className = className; parent.appendChild(div); } function downloadError() { downloadStatus.innerText = "下载帖子出错。"; }当调用 HTTP 请求完毕,我们接着执行 processPosts 函数,其参数请求对象(a request object)一如 XMLHttpRequest 的那样子,好比我们所关心的 responseXML 属性,这个就是我们所请求的结果,也就是 RSS 数据。RSS 本身也是一份标准的 XML 文档,于是我们可用XPath表达式选取 RSSfeed 里面的节点,提取每项条目的标题、pubDta 和内容等等,最后渲染到 div 元素中。对于既往的 “TheOld New Thing” 读者,看到程序输出的样子也会觉得是相似的。
有人会问,是否 xhr 函数会工作,因为 web 服务器的生产的页面可能会失败的。可以工作起来的原因在于使用 JavaScript Metro 式程序是运行在一个本地而且安全的上下文环境中,仅仅只能使用程序所列明的请求和用户所限定的功能。
接下来
你已经懂得 Metro App 怎么用 JS 编写的一点门径了,但是所接触到 API 只是 Win 类库中的一小部分。接下来将要预告的是《扩展你的第一个Win Metro式程序 Extending your first Windows Metro style app》,与您一道发现 Windows Runtime 和控件的奥秘!