使用-HTML5-和-JavaScript-开发-Windows-商店应用-全-

使用 HTML5 和 JavaScript 开发 Windows 商店应用(全)

原文:zh.annas-archive.org/md5/8F13EC8AC7BDB8535E7218C5DDB48475

译者:飞龙

协议:CC BY-NC-SA 4.0

序言

使用 HTML5 和 JavaScript 开发 Windows Store 应用 是一本实践性强的指南,涵盖了 Windows Store 应用的基本重要特性以及示例代码,向您展示如何开发这些特性,同时学习 HTML5 和 CSS3 中的新特性,使您能够充分利用您的网页开发技能。

本书内容覆盖范围

第一章, HTML5 结构, 介绍了新 HTML5 规范中的语义元素、媒体元素、表单元素和自定义数据属性。

第二章, 使用 CSS3 进行样式设计, 介绍了 CSS3 在开发使用 JavaScript 的 Windows Store 应用时会频繁用到的增强和特性。本章涵盖了以下主题:CSS3 选择器、网格和弹性盒布局、动画和转换、以及媒体查询。

第三章, Windows 应用的 JavaScript, 介绍了 JavaScript 的 Windows 库及其特性,并突出显示了用于开发应用的命名空间和控件。

第四章, 使用 JavaScript 开发应用, 介绍了开始使用 JavaScript 开发 Windows 8 应用所需的工具和提供的模板。

第五章, 将数据绑定到应用, 描述了如何在应用中实现数据绑定。

第六章, 使应用响应式, 描述了如何使应用响应式,以便它能处理不同屏幕尺寸和视图状态的变化,并响应缩放。

第七章, 使用磁贴和通知使应用活跃, 描述了应用磁贴和通知的概念,以及如何为应用创建一个简单的通知。

第八章, 用户登录, 描述了 Live Connect API 以及如何将应用与该 API 集成以实现用户认证、登录和检索用户资料信息。

第九章, 添加菜单和命令, 描述了应用栏、它如何工作以及它在应用中的位置。此外,我们还将学习如何声明应用栏并向其添加控件。

第十章, 打包和发布, 介绍了我们将如何了解商店并学习如何使应用经历所有阶段最终完成发布。同时,我们还将了解如何在 Visual Studio 中与商店进行交互。

第十一章,使用 XAML 开发应用,描述了其他可供开发者使用的平台和编程语言。我们还将涵盖使用 XAML/C#创建应用程序的基本知识。

本书需要你具备的知识

为了实施本书中将要学习的内容并开始开发 Windows Store 应用,你首先需要 Windows 8。此外,你还需要以下开发工具和工具包:

  • 微软 Visual Studio Express 2012 用于 Windows 8 是构建 Windows 应用的工具。它包括 Windows 8 SDK、Visual Studio 的 Blend 和项目模板。

  • Windows App Certification Kit

  • Live SDK

本书适合谁

这本书适合所有想开始为 Windows 8 创建应用的开发者。此外,它针对想介绍 standards-based web technology with HTML5 和 CSS3 的进步的开发者。另外,这本书针对想利用他们在 Web 开发中的现有技能和代码资产,并将其转向为 Windows Store 构建 JavaScript 应用的 Web 开发者。简而言之,这本书适合所有想学习 Windows Store 应用开发基础的人。

约定

在这本书中,你会发现有几种不同信息类型的文本样式。以下是这些样式的一些示例及其含义的解释。

文本中的代码词汇如下所示:“createGrouped方法在列表上创建一个分组投影,并接受三个函数参数。”

代码块如下所示:

// Get the group key that an item belongs to.
  function getGroupKey(dataItem) {
  return dataItem.name.toUpperCase().charAt(0);   
}

// Get a title for a group
  function getGroupData(dataItem) {
  return {
    title: dataItem.name.toUpperCase().charAt(0);
  }; 
}

新术语重要词汇以粗体显示。例如,你在屏幕上看到的、菜单或对话框中的单词,会在文本中以这种方式出现:“你将能够为应用程序 UI 设置选项;这些选项之一是支持的旋转。”

注意

警告或重要说明以这种方式出现在盒子里。

技巧

技巧和小窍门像这样出现。

读者反馈

读者对我们的书籍的反馈总是受欢迎的。告诉我们你对这本书的看法——你喜欢或可能不喜欢的地方。读者反馈对我们开发您真正能从中获得最大收益的标题非常重要。

要发送给我们一般性反馈,只需发送电子邮件到<feedback@packtpub.com>,并在消息主题中提及书籍标题。

如果你在某个主题上有专业知识,并且你对编写或贡献书籍感兴趣,请查看我们网站上的作者指南:www.packtpub.com/authors

客户支持

既然你已经成为 Packt 书籍的骄傲拥有者,我们有很多东西可以帮助你充分利用你的购买。

勘误

尽管我们已经竭尽全力确保内容的准确性,但错误仍然可能发生。如果您在我们的书中发现任何错误——可能是文本或代码中的错误——我们非常感谢您能向我们报告。这样做可以避免其他读者感到沮丧,并帮助我们改进本书的后续版本。如果您发现任何错误,请访问www.packtpub.com/submit-errata,选择您的书籍,点击错误提交表单链接,并输入您的错误详情。一旦您的错误得到验证,您的提交将被接受,并且错误将被上传到我们的网站或添加到该标题下的错误列表中。您可以通过www.packtpub.com/support选择您的标题查看现有的错误。

版权侵犯

互联网上版权材料的侵犯是一个持续存在的问题,涵盖所有媒体。在 Packt,我们非常重视版权和许可的保护。如果您在互联网上以任何形式发现我们作品的非法副本,请立即提供位置地址或网站名称,以便我们可以寻求解决方案。

如果您发现任何可疑的版权侵犯材料,请通过<copyright@packtpub.com>联系我们并提供链接。

我们非常感谢您在保护我们的作者和我们提供有价值内容的能力方面所提供的帮助。

问题反馈

如果您在阅读本书的过程中遇到任何问题,可以通过<questions@packtpub.com>联系我们,我们会尽最大努力为您解决问题。

第一章: HTML5 结构

HTML5 引入了新的元素和属性,以更整洁的结构、更智能的表单和更丰富的媒体,这使得开发者的生活变得更加容易。HTML5 功能根据其功能分为几个组,新的结构元素属于语义组,包括结构元素、媒体元素、属性、表单类型、链接关系类型、国际化语义和附加语义的微数据。HTML5 有很多增加和增强的内容,所有这些都是为了更好地在网络上呈现内容。当你开发 Windows 8 应用时,你会使用其中许多功能;使用 Windows 8 开发的区别在于,至少在 Windows Store 应用层面,你不必担心浏览器的兼容性,因为 Windows 8 是一个使用最新网络标准的 HTML5 平台。你所使用的 HTML5 和 CSS3 的一切都为你代码中提供,并保证在应用程序中工作。最新版本的 Visual Studio(VS 2012)包括一个新 HTML 和 CSS 编辑器,提供对 HTML5 和 CSS3 元素和片段的全面支持。

在本章中,我们将涵盖以下主题:

  • 语义元素

  • 媒体元素

  • 表单元素

  • 自定义数据属性

理解语义元素

HTML5 标记语义比其前辈更强,这要归功于描述页面内容结构的新语义元素。语义元素的列表包括以下内容:

  • <header>标签定义了文档或节的头部。它在页面或节中包裹标题或一组标题,并且它还可以包含诸如徽标、横幅和主要导航链接等信息。在页面中你可以有多个<header>标签。

  • <nav>标签代表主要的导航链接。通常它绑定在头部。

  • <section>标签包裹可以按主题组合的相关内容。一个<section>标签可以包括一个<header><footer>标签。

  • <footer>标签代表关于页面或节的内容,例如,相关链接、隐私条款和版权信息。在页面中你可以有多个<footer>,它与<header>标签相同。

  • <article>标签代表可以独立于整个文档使用的独立内容,例如,一篇博客文章。<article><section>非常相似,因为两者都是独立的标签并包含相关内容;然而,如果它的内容可以通过原子或 RSS 提要进行联合(syndication),那么<article>元素更为合适。

  • <aside>标签代表与页面内容相关但分离的部分,因为它可以被移除而不会影响页面的主要内容。典型的用法是侧边栏。

  • <address>标签代表最近的<article>父元素的联系信息,如果存在的话,或者适用于整个文档的父<body>元素。

将这些新元素全部放在一个页面中会产生以下的标记:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Developing for Windows 8</title>
</head>
<body>
  <header>
    <a href="default.html">
      <h1>The Courses</h1>
      <img src="img/logo.png" alt="Book Logo">
    </a>
    <nav>
      <ul>
        <li><a href="home.html">Home</a></li>
        <li><a href="about.html">About</a></li>
      </ul>
    </nav>
  </header>
  <section>
    <article>
      <h2></h2>
      <p></p>
      <address>
        Written by <a href="mailto:xyz@abc.com">Demo Author</a>.<br>
        Found at: Demo.com <br>
        Address, Street<br>
        UK
      </address>
    </article>
    <article>
      <h2></h2>
      <p>content</p>
    </article>
  </section>
  <aside>
    <h2></h2>
    <ul>
      <li></li>
      <li></li>
      <li></li>
    </ul>
    <p></p>
  </aside>
  <footer>
    <p></p>
    <p>Copyright &copy; 2013 Packt</p>
  </footer>
</body>
</html>

引入内置媒体元素

HTML5 引入了新的媒体元素,如<audio><video>,这些可以被认为是 HTML 早期版本中图像之后的媒体类型的新的革命。这两个元素使得在 HTML 页面/文档中嵌入媒体变得非常简单,并通过HTML5 媒体元素 API提供内置媒体支持。根据 W3C 最新的规范,我们可以这样定义<video><audio>

  • <video>标签是一个媒体元素,用于播放视频或电影以及带字幕的音频文件。

  • <audio>标签是一个媒体元素,其媒体数据是音频,即声音或音频流。

<audio><video>元素分别播放音频和视频文件。它们之间的唯一区别是,<audio>元素没有用于视觉内容的播放区域,这与<video>元素相反。

在 HTML5 之前,我们需要一个插件来播放音频或视频文件,这需要编写大量的标记代码。没有 HTML5,嵌入媒体元素从未如此简单;只需放入一个<audio>标签,就可以得到带有播放控制的媒体播放器,仅需两行代码。它几乎与之前的<img />标签一样。参考以下代码:

<audio src="img/audio.mp3" controls>
</audio>

上一个例子会在 Internet Explorer 9 (IE9)上看起来像以下的屏幕截图,并且可能因浏览器而异:

引入内置媒体元素

上面的代码展示了<audio>标签的最简单形式,但<audio>标签还有更多的属性和选项。参考以下代码:

<audio controls autoplay loop>
  <p>Your browser does not support the audio element. Click <a href="content/Elsie.mp3"> here </a> to download the file instead.
  </p>
  <source src="img/audio.mp3" type="audio/mp3" />
  <source src="img/audio.ogg" type="audio/ogg" />
</audio>

首先,注意<audio>元素内的<p>标签中的内容。这部分内容是备用文本,只有在浏览器不支持<audio>标签时才会使用。它通过告知用户这个问题,为旧版网页浏览器提供一个优雅的回退方案,并且我们可以添加一个链接允许下载这个音频文件。这样,用户就不会只是站在那里想知道发生了什么。这是最简单的回退方式;你也可以用 JavaScript 达到同样的效果。

上面的代码片段还展示了一些<audio>元素的属性。根据 W3C 规范,srccontrolsautoplaylooppreloadmediagroupmuted是两个媒体元素(即<audio><video>)共同的属性。

  • controls属性在网页上显示音频的标准 HTML5 控件,控件的设计在不同浏览器代理之间可能会有所不同。

  • autoplay属性在 DOM 加载完成后自动播放音频文件。

  • loop 属性 enable 自动重复。

  • mediagroup 属性通过媒体控制器将多个媒体元素链接在一起。

  • muted 属性设置了音频文件默认静音状态。

  • preload 属性向用户代理提供了关于作者认为将导致最佳用户体验的提示。它的值可以是 nonemetadataauto

    • none:这个值提示浏览器,网页不期望用户需要媒体资源。

    • metadata:这个值提示浏览器获取资源元数据(维度、轨道列表、持续时间等)。

    • auto:这个值提示浏览器在没有任何风险的情况下优先考虑用户的需求。空值,如只是添加了 preload 属性,映射到 auto 值。

您可以像 controls="controls" 一样为属性指定值,这将具有相同的行为。但为了简化代码和减少代码量,您可以省略这个属性的值;同样的适用于 loopautoplaymuted。您可以通过使用 src 属性或 <source> 元素来指定媒体资源。

注意

属性覆盖了元素。

媒体资源(音频或视频)有一个 MIME 类型,另外还有一个编解码器,如下代码所示:

<source src="img/video.ogv" type="video/ogg; codecs="theora, vorbis" />

type 属性设置值必须在 <source> 元素内完成。如果浏览器/用户代理不支持其类型,将避免下载资源。您可以为不同的浏览器添加多种格式的音频/视频,以确保播放支持。浏览器代理将查看 <source> 元素;如果它无法渲染第一个类型,它将跳到下一个 <source> 以验证其类型,依此类推。为此,您必须检查不同浏览器中 <audio><video> 元素支持的 MIME 类型列表。浏览器不仅检查 MIME 类型,还检查指定的编解码器。所以,即使浏览器代理可以渲染资源类型,如果编解码器不受支持,视频/音频也不会加载。

以下表格列出了主要视频格式在主要浏览器中的支持情况:

格式 IE9+ Chrome Firefox Opera Safari
WebM (VP8 编解码器)
MP4 (H.264 编解码器)
OGV (OGG THEORA 编解码器)

从前面的表格列表中,我们可以得出结论,在您的 HTML5 视频中提供 WebM 和 MP4 格式的媒体资源将保证在所有主要浏览器的最新版本中加载。这个理论在 Visual Studio 2012 中得到了加强,它为 HTML5 标签提供了完整的 Intellisense 支持。当你插入以下 HTML5 <video> 元素的代码片段时,它在 <video> 标签内列出 3 个 <source> 元素:

<video controls="controls">
  <source src="img/file.mp4" type="video/mp4" />
  <source src="img/file.webm" type="video/webm" />
  <source src="img/file.ogv" type="video/ogg" />
</video>

<video>元素还包括一个poster属性,用于指定在没有视频数据可用或直到用户点击播放按钮时在视觉内容区域显示的图像的路径。出于广告目的,你可以使用图像或视频中的帧,让用户了解视频的样子。如果你没有指定海报图像,并且autoplay属性没有设置,浏览器可能会显示一个填充<video>元素尺寸的黑色盒子。例如,以下代码显示了两个相似视频的代码示例之间的区别,第二个视频指定了海报:

<video id="video" controls width="400">
  <source src="img/video.mp4" type="video/mp4" />
</video>
<video id="videoWithPoster" controls width="400" poster="http://msdn.microsoft.com/br211386.5_GetStarted_484x272px.jpg">
  <source src="img/video.mp4" type="video/mp4" />
</video>

这段标记输出的结果将在屏幕上产生以下内容:

介绍内置媒体元素

你可能会注意到,在之前的示例中我们对两个视频指定了width值为400<video>元素接受标准的 HTMLwidthheight属性。如果没有设置widthheight的值,视觉内容区域将扩展到视频的原生尺寸。建议在<video>元素上设置widthheight属性,从而避免扩展到全尺寸,并且按照期望的观看尺寸对视频进行编码。

注意

widthheight属性的值不接受单位。该值表示 CSS 像素,例如,width=400width=400px相同。

有一些 JavaScript 方法、属性和 DOM 事件是 HTML5 标准的一部分,与这些新元素相关。你可以程序化地读取和设置属性,例如src路径和<video>标签的尺寸(widthheight)。你可以使用 JavaScript 方法加载音频和视频,然后播放和暂停媒体资源。你还可以编写代码来处理媒体元素触发的不同 DOM 事件,例如onplayingonprogress(加载进度)、onplayonpause。例如,你可以通过移除controls属性并从单独的按钮调用播放和暂停媒体资源的函数来禁用元素显示的默认控件。

下面的代码列表显示了如何使用 JavaScript 播放和暂停视频。我们首先需要通过调用布尔属性.paused来检测视频文件当前的状态,如果为真,则相应地调用play()pause()方法:

var testVideo = document.getElementById('myVideo');
if (testVideo.paused)
  testVideo.play();
else
  testVideo.pause();

在之前的代码中,我们声明了一个变量testVideo,并将其赋值给 DOM 中的myVideo元素。假设该元素被分配了一个 ID,你可以使用名称、标签名或元素在 DOM 层次结构中的位置来检索元素。

高级媒体与 JavaScript

媒体元素拥有丰富的 API,可以纯 JavaScript 进行访问。利用 JavaScript,我们可以向媒体元素添加许多功能。您可以操纵媒体资源,给它样式,旋转视频,同步播放两个或更多的媒体元素,在媒体资源加载时显示进度条,动态调整视频大小等等。

以下代码示例为 timeupdate 事件添加了功能,该事件获取视频的当前播放时间(以秒为单位)并在一个单独的 div 中显示它。

以下是的 HTML 代码:

<div id="tInfo"></div>
<video id="myVideo" autoplay controls>
  <source src="img/w8.mp4" type="video/mp4" />
</video>

以下的 JavaScript 代码:

var video = document.getElementsById('myVideo');
var tInfo = document.getElementById('tInfo');
video.addEventListener('timeupdate',function(event){
tInfo.innerHTML = parseInt(video.currentTime);
}, false);

使用 JavaScript addEventListener 方法提供 timeupdate 事件的处理程序。它接受三个参数,具有以下基本语法:

WinJS.Application.addEventListener(type, listener, capture);

type 参数指定了要注册的事件类型,而 listener 是与事件关联的事件处理函数,第三个参数 capture 是一个布尔值,用于指定事件处理程序是否注册在捕获阶段。

此外,您可以将 <video> 元素与画布结合使用,允许您实时操作视频数据并添加各种视觉特效。

介绍功能丰富的表单元素

表单和 <form> 元素是任何应用程序或网站的重要组成部分,从登录表单到完整的联系或注册表单。在 HTML4 中,<form> 元素非常简单,对于任何功能或高级样式,JavaScript 都是必需的。而对于任何交互,或者数据提交和验证,都要求服务器和客户端脚本,如果浏览器中禁用了脚本,其功能就会受到限制。HTML5 通过新的属性和输入类型对 <form> 元素进行了重大改进,并添加了诸如基于浏览器的验证和 CSS 样式等功能,为填写表单的用户提供了更好的体验,并为创建表单的开发人员提供了所有可能的简单性。

一个丰富的 <input> 标签

<input> 元素引入了 type 属性的新值。

HTML5 在 HTML4 我们已经熟悉的 <input> 类型中增加了 13 个新类型,如 textcheckbox。添加这些类型后,<input> 控制现在支持如 rangedatenumbertelephoneemailURL 等类型。而这些新的 <input> 类型为元素本身添加了智能行为。

以下是这些类型的表格列表:

<input> 类型 描述
--- ---
tel 它期望一个电话号码。
search 它提示用户输入他们想要搜索的文本,并在支持它的浏览器上向输入元素添加一个搜索图标。
url 它期望一个 URL。
email 它期望一个电子邮件地址或由逗号分隔的电子邮件地址列表。
datetime 它期望一个带有 UTC 时区的日期和时间。
date 它期望一个日期。
` month
` week
` time
` datetime-local
` number
` range
` color

除了向<input>类型添加新特性外,还增加了对新现有特性的支持,例如文件输入元素,现在支持使用multiple属性进行多文件选择。当表单提交时,浏览按钮将显示文件对话框,然后你可以从本地磁盘或SkyDrive中选择文件;文件可以作为表单数据的一部分发送到服务器。

您还可以利用表示任务进度的progress元素,如 W3C 所指定。它可以用来显示大文件正在上传或媒体资源正在加载的进度。任务的进度由此元素的两个属性决定:

  • value属性,表示进度已完成多少

  • max属性,表示直到任务完成所需的总工作量

以下代码使用progress元素和一个按钮,脚本将其参数中的值添加到其现有值中。当你加载示例并尝试它时,你将看到进度条 visually updating the completion progress。

以下是的 HTML 代码:

<button id="clickBtn" onclick="updateProgress(10)">Update Progress</button>Progress: <progress id="prog" max="100"></progress>

以下是的 JavaScript 代码:

<script>
//get the progress element and add the value to it with every click var progressBar = document.getElementById('prog');
function updateProgress(newValue){ 
progressBar.value = progressBar.value + newValue;
}
</script>

简单的验证

HTML5 的新<input>类型以及验证属性,如requiredpattern,还有伪 CSS3 选择器允许基于浏览器的验证,这样你可以在不编写一行代码或脚本的情况下捕获表单的输入错误。这在过去是不可能的,需要自定义 JavaScript 代码或 JavaScript 库。基本上,它提供了无 JavaScript 的客户端表单验证。

我们将从最简单的验证开始,即填写一个必填字段。为了实现这一点,我们需要向<input>元素添加required属性。

required属性可以设置在类型为textURLemailcheckboxradio<input>元素上,以及selecttextarea元素上。它是一个布尔属性,只能设置在元素上。

我们通过简单地向<input>元素添加required属性来指定字段的值为必填。在下面的代码列表中,你会发现带有required属性的几个<input>元素:

<form action="/" method="post">
  <label>Checkbox:</label>
    <input type="checkbox" required />
  <label>Radio:</label>
    <select>
      …
    </select>
  <label>Text:</label>
    <input type="search" required />
  <label>Range:</label>
    <input type="range" min="5" max="10" step="5" />
  <label>URL:</label>
    <input type="url"  required />
  <label>File:</label>
    <input type="file" accept=".mp3" />
    <input type="submit" name="submit" value=" Submit " />
</form>

一旦添加了required属性,然后当你点击提交按钮时,表单中的所有字段都将进行验证;如果任何字段不正确,将返回错误。必填字段会被突出显示,而且,默认消息会通知用户这些字段在表单中是必须的。

你可以看到下面的截图显示了前面代码的输出:

轻松验证

我们可以使用 CSS3 伪选择器required应用一个或多个样式(关于这方面的更多信息将在下一章中介绍)。例如,下面的样式添加了一个 CSS3 伪类required,它将寻找文档中具有required属性的所有input元素,并用yellow border-color来设置样式。

input:required {
  border-color: Yellow;
}

如果你想对表单中所有非必填元素应用一种样式,那是非常简单的;只需添加optional伪类,并像我们对required类所做的那样给它一个样式。在下面的代码中,我们给所有没有required属性的input元素应用了LightGray border-color

input:optional {
  border-color: LightGray; 
}

HTML5 表单不仅对必填字段进行验证,而且还检查字段值的内容,并自动验证,就像在 URL 和email输入类型中一样,或者使用pattern属性。pattern属性使用正则表达式来定义元素值必须匹配的有效格式,例如,电话号码或社会保障号码。

下面的例子展示了password字段的语法,该字段是必填的,并且必须有有效的输入,最小长度为八个字符。在这里,默认的验证消息被title属性中提供的文本替换:

<input type="password" required pattern="[^\s]{8}[^\s]*" title="Passwords must be at least 8 characters long."/>

还有更多属性可以增加验证技术,比如placeholder,它提供了一个在用户开始在元素内输入文字前以浅色文字显示的提示信息;这个提示可能是关于用户应该在字段中输入的值。例如,你可以在email字段中添加一个示例电子邮件地址,如:

<input type="email" placeholder="email@example.com" />

你可以使用maxlength属性检查texttextarea输入中允许的最大字符数。此外,我们还有minmaxstep属性与range元素一起使用,以验证该元素输入的值。minmax属性检查可以输入的最小和最大值,而step属性检查允许的值。

你还可以通过accept属性指定可接受的文件 MIME 类型。正如你在前面的代码列表中可能注意到的,accept属性被添加到了<input type="file" />元素中,这是唯一与之使用的元素。一旦你把这个属性添加到文件控件中,然后当你尝试使用 Windows 8 文件资源管理器浏览文件时,只有accept列表中的类型才会显示。

HTML5 表单验证是默认行为;不需要编写代码来激活它,但您可以通过在提交按钮或任何<input>元素上添加formnovalidate属性来关闭它。这个属性允许表单在没有经过验证的情况下提交。

分配自定义数据属性

随着 HTML5 的出现,我们现在有能力为任何 HTML5 元素分配自定义数据属性。W3C 将其定义为:

用于存储页面或应用程序私有自定义数据的属性,如果没有更合适的属性或元素,则可以使用该属性。

这些新的自定义数据属性由两部分组成:

  • 属性名称:它必须以data-前缀开头,后跟至少一个字符,且不应包含大写字母。

  • 属性值:它必须是一个字符串值

让我们像下面的代码示例那样给<div>标签添加一个自定义属性:

<div id="bookList" data-category="TechnicalBooks">
Developing for windows 8
</div>

你可以看到自定义属性名data-category和属性值TechnicalBooks被分配给<div>元素。这些数据可以通过使用原生的getAttributesetAttribute方法来检索和更新,因为自定义数据属性被认为是它们所使用的页面的组成部分。下面的代码示例展示了如何使用原生的 JavaScript 来操作自定义属性:

function getSetCategory() {
  var bookList = document.getElementById("bookList");
//get the value of the attribute
  var bookCategory = bookList.getAttribute('data-category');
//set the value for the attribute
  bookList.setAttribute('data-category', 'HealthBooks');
//remove the attribute
  bookList.removeAttribute('data-category');
}

HTML5 规范明确指出,数据属性不应用来替代已存在的属性或可能更具有语义 appropriate 的元素。例如,在span元素中添加一个 data-time 属性来指定时间值是不恰当的,如下面的代码所示:

<span data-time="08:00">8am<span>

最合适且更具语义的元素是一个time元素,如下面的代码所示:

<time datetime="08:00">8am</time>

当开发 Windows 8 应用时,我们可以使用 Windows 为 JavaScript 提供的库(WinJS)来实现将数据与 HTML 元素更高级的绑定。Win8 JavaScript 库利用 HTML 的data-*属性提供了一种简单的方式来程序化实现数据绑定。

概要

在 HTML5 中,有新的语义丰富的元素,可以传达它们使用的目的。有媒体元素允许您轻松地向应用程序添加音频和视频,还有新的输入类型和属性,您可以使用它们创建智能和交互式的表单,并实时地将它们与数据绑定,所有这些都比以往任何时候的标记和代码都要少。

在下一章中,我们将查看在为 Windows 8 开发时可用的丰富的新 CSS3 特性,以及我们如何使用它们来为我们的 HTML 应用样式和布局。

第二章.使用 CSS3 进行样式设计

HTML 定义了文档/页面结构并列出了包含的元素。但定义这些元素的布局、定位和样式是 CSS 的唯一责任。层叠样式表(CSS),正如其名,基本上是一张包含一系列样式规则的表。每个 CSS 样式规则将一个选择器,它定义将要样式的内容,链接到一个声明块,其中包含一个或一组样式,进而定义要应用于相关选择器的效果(s)。基本样式规则的语法看起来像这样

selector { property: value; property: value; }

在本章中,我们将回顾以下主题:CSS3 选择器、网格和 Flexbox、动画和转换,以及媒体查询。这些主题涵盖了在用 JavaScript 开发 Windows Store 应用时经常使用的 CSS3 的一些特性。

CSS3 选择器的威力

CSS 选择器非常强大,在格式化 HTML 文档时非常方便。使用选择器有时会有些棘手,因为精确地选择你想要的内容,并确保应用的样式规则只影响你意图中的元素,是一项繁琐的任务。但是,当使用正确的选择器正确地完成时,结果是非常有价值的。掌握选择器的使用将导致更简单的 CSS,最小化冗余样式和通过类和 ID 对 HTML 进行过度定义的可能性,从而确保更好的性能。选择器可以是一个 HTML 元素、一个类、一个元素 ID,甚至可以是元素在 DOM 中的位置。

以下是一份 CSS 选择器的列表;我们将从基础的选择器开始,进而介绍 CSS3 中新增的选择器:

  • 星号(*)符号:这是一个万能选择器,被称为通用类型选择器,用于定位文档中的每一个元素。它经常与 CSS 重置一起使用,以重置所有默认样式。

    * { margin: 0; }
    
  • HTML 元素:它被称为类型选择器,用于根据它们的类型选择文档中的所有元素。例如,下面的选择器将定位 DOM 中的每一个<p>元素,把文本颜色改为红色,并加下划线。

    p { color: red; text-decoration: underline; }
    

    提示

    使用<body>元素作为选择器将定位文档的正文,从而选择每一个元素,就像你正在使用星号(*)一样。

  • ID 选择器:它由元素 id 属性中的值前缀哈希符号(#)指定。ID 应该是元素的名称,更重要的是,它必须是唯一的。名称应该是对元素的清晰引用。例如,对于一个nav元素来说,有一个id值为mainMenu会很清晰。例如:

    <nav id="mainMenu"></nav>
    
    

    另外,唯一性意味着在页面上不应该有其他具有id值为mainMenu的元素。由于id应该始终是唯一的,选择器将在 HTML 文档中只针对一个元素。例如,如果你有如下的<div>元素,其id值为logo

    <div id="logo"></div>
    

    则相应的选择器将是:

    #logo { float: left; width: 200px; } 
    
  • 类选择器:它由一个类名前缀和一个点号(.)组成,目标是指具有匹配类名的所有元素。这个选择器的基本语法如下:

    .highlighted { font-weight: bold; background-color:yellow; }
    

具有这个类名的任何元素都将拥有粗体文本和黄色背景颜色。当您想要为多个元素设置样式时,应该使用类,特别是有一组共通之处的元素。记住,与id属性相反,类名永远不能用来唯一标识一个元素。此外,class属性可能有多个值;同样,相同的类也可能适用于多个元素。尽管类选择器的使用可能看起来很通用,但您可以通过在前缀类型选择器来更具体地使用它。例如,下面的代码片段将只针对具有highlighted类的<div>元素:

div.highlighted { font-weight: bold; background-color: yellow; } 

另外,您可以连锁类选择器来针对具有所有指定类名的所有元素。

属性选择器

属性选择器用于根据元素的属性来选择元素。它首先检查属性是否存在;如果存在,它再检查属性的值。属性应该被包含在方括号内。如果方括号内只包含属性名,它将检查该属性是否存在于元素中。这就是它也被称为存在选择器的原因。在下面的代码片段中,选择器将只针对具有title属性的锚元素:

a[title] { text-decoration: none; color: #000; }

前面的语法在检查没有值的属性时很有帮助。如果你记得,在前一章节我们提到了一些属性不需要值,比如<input>元素的required属性,或者音频和视频元素的loop属性。下面的选择器将寻找所有具有loop属性的音频元素并隐藏它:

audio[loop] { display: none; }

为了精确匹配指定的属性值,我们将使用带有等号(=)的等价属性,并将值用引号括起来。所以,如果我们想要针对所有type属性值为email的输入元素,语法将如下所示:

input[type="email"] { text-decoration: none; color: #000; }

另外,在属性选择器类别下,我们有前缀选择器或“以...开始”的属性选择器,用于检查属性是否以某个值开始。以下语法将匹配所有id值以home开始的图片。例如,如果你想定位首页上的所有图片,可以将home添加到id中,从而有homeLogohomeBanner等,并为其应用 10 像素的边距:

img[id^='home'] { margin:10px; }

同样,我们有后缀选择器或“以...结尾”的属性选择器,它将选择所有属性值以你所指定的值结尾的元素。后缀选择器在等号(=)之前用美元($)符号标记,语法如下:

a[href$=".jpg"] { color: red; }

这将匹配所有href属性值以.jpg结尾的锚点元素:

另一个属性选择器是子字符串选择器,也称为“包含”选择器。正如其名,它匹配包含选择器中指定的值的属性值。它用星号(*)符号在等号(=)之前标记,语法如下:

ul[id*="Nav"] { float: left; list-style-type: none; }

前面的语法将匹配所有含有Nav字符串的<ul>元素 ID。例如,你有多个用于导航目的的<ul>元素,并标记有诸如secondaryNavsidebarNav等 ID:

我们也有一种连字符选择器,用|=标记,它用于匹配后面紧跟连字符的完全相等的属性值。你可能很少使用这个选择器,但它的典型用途是用于包含连字符的值,例如lang属性。下面的列表将目标定位在与"en"完全匹配,且后面紧跟连字符的元素上,并将返回enen-usen-uk等:

ul[lang|="en"] { display: none; }

最后一个属性选择器将是空白符选择器,它针对的是在空格分隔的值列表中完全匹配指定属性值的元素。在以下代码片段中,我们有一个带有自定义data-属性的<p>元素,包含三个空格分隔的值,分别为new events local,选择器将匹配这个元素,因为它的data-post-type值与events完全匹配。

以下为 HTML 代码:

<p data-post-type="new events local"></p>

CSS 代码如下:

p[data-post-type~="events"] { float: left; color: red }

注意

注意,在 HTML5 中,任何以data-开头的属性都是有效的,与其前身只认为识别的属性有效的规定不同。

组合选择器

一个 CSS 选择器可以包含多个选择器,即简单选择器的组合。组合选择器包含多个简单选择器,由一个组合符连接。组合符是一个表示选择器之间关系的符号。CSS2 中已经有三个不同的组合符,CSS3 增加了一个额外的。以下列出四个选择器,所使用的组合符以及每个选择器匹配的内容:

选择器 组合符 目标
后代 空格字符 匹配那些是指定元素后代的元素。
直接后代(子选择器) > 匹配那些是指定元素直接后代的元素。
相邻兄弟 + 匹配那些是指定元素相邻兄弟(紧随其后的)的元素。
一般兄弟 ~ 匹配那些是指定元素相邻兄弟的元素。

以下选择器描述如下:

  • 后代选择器:由空格字符作为组合符,它将选择所有指定元素的后代元素。仿佛我们在第一个简单选择器上应用了一个额外的过滤器。第一个选择器代表父元素,第二个是要匹配的子(后代)元素。例如,以下代码片段会匹配所有<li>元素作为其父元素的锚点元素:

    HTML 代码如下:

    <ul>
        <li><a href="#">Item 1</a></li>
        <li><a href="#">Item 2</a></li>
        <li><a href="#">Item 3</a></li>
    </ul>
    

    CSS 选择器如下:

    li a { text-decoration: none; color: #000; } 
    
  • 直接后代选择器:由大于号(>)作为组合符标记,基本形式为 E>F,匹配 E 元素的每个直接后代(子)F 元素。在以下代码片段中,只有<div>元素的直接子<p>元素会被染成蓝色,其余的则不会。

    HTML 代码如下:

    <div>
        <p>some content inside a div</p>
    </div>
    <p> standalone content …</p>
    <div>
        <p> contentinside a div </p>
    </div>
    <header>
        <p> content inside a header </p>
    </header>
    

    CSS 代码如下:

    div > p { color: Blue; } 
    
  • 相邻兄弟选择器:由加号(+)作为组合符标记,匹配所有紧随父元素之后的兄弟元素。所以,兄弟元素之间不能有其他元素。如果这有点复杂,下面的例子会解释清楚。选择器只会把一个<p>元素染成红色。

    HTML 代码如下:

    <h1>Heading</h1>
    <p>This p element is a sibling and adjacent to the h1 
    </p>
    <p>This p element is a sibling but not adjacent to the h1
    </p>
    

    CSS 代码如下:

    h1 + p { color: Red; } 
    
  • 一般兄弟选择器:由波浪号(~)作为组合符标记,是 CSS3 的新增功能。它用于选择所有给定元素的兄弟元素。所以,如果我们把选择器应用到前面的例子中的 HTML 代码上,两个<p>元素都会匹配并染成红色,因为它们都是h1的兄弟元素。

    h1 ~ p { color: Red; } 
    

伪类选择器

伪类类似于类,但由于它是内置的,您不需要在 HTML 代码中显式添加它。此外,它在语法上也有所不同;类选择器前面有一个点(.),而伪类选择器前面有一个冒号(:)。在其基本形式中,伪类选择器将采用以下形式:

selector:pseudo-class { property: value }

您可以指定没有选择器的伪类,它将调用默认类型选择器。所以,如果我们单独指定:hover,它将匹配所有元素,并将样式规则应用于文档中可以悬停的任何内容。否则,您可以更详细地将对特定 HTML 元素的伪类选择器。例如,以下代码片段将在悬停时为所有<p>元素应用粉红色:

p:hover { color: pink; }

在 CSS3 之前,伪类就已经存在,您可能对著名的:hover:visited:active伪类很熟悉,这些伪类代表锚元素的不同的状态。CSS3 引入了许多更强大的伪类,如:required:valid:nth-child(n):first-child:last-child:only-child:first-of-type:last-of-type等。

伪元素选择器

伪元素代表元素的某些部分,如段落的第一行,或元素后面的部分。伪元素类似于一个伪类,它作为类的行为,但是内置的,不需要在 HTML 代码中定义。伪元素通过双冒号(::)来区分,这个语法是在 CSS3 中引入的。需要注意的是,在 CSS3 之前引入的所有伪元素都使用单个冒号(:),类似于伪类的语法。

以下代码片段将选择由content样式属性定义的<p>元素后的所有生成内容:

HTML 代码如下:

<p>Paragraph content goes here</p>

CSS 代码如下:

p::after {
  content: " 'I come after a paragraph' ";
  color: blue; background-color: yellow;
}

输出结果将是:

段落内容放在这里 '我在段落后'

下面是伪元素的表格:

::first-letter 匹配元素中的第一个字母。
::first-line 选择元素中的第一行。
::before 选择元素生成的内容之前。
::after 选择元素生成的内容之后。
::selection 选择用户可能已经高亮显示的任何内容,包括可编辑文本字段中的文本,如输入类型为文本的元素,或具有contenteditable属性的任何元素。

提示

虽然您可以通过使用 JavaScript 向您的 HTML 代码中添加类来以编程方式实现相同的行为,但通过向您的选择器中添加伪类和伪元素更为简单;此外,它还可以使您的代码更清晰。

使用 Grid 和 Flexbox 创建流体布局

当涉及到实施由 Microsoft 设定的构建吸引人、直观且互动的 Windows 8 应用的设计原则时,布局非常重要。通常,使用 HTML 结构元素(如<div><table>)和定位样式规则定义页面布局。

但是现在,使用 CSS3 高级布局功能(即网格布局和Flexbox灵活盒)布局)有一种更灵活的方法来实现。这些布局系统允许您轻松实现适应性和流体布局。

网格布局

它为 Windows 8 应用提供了一种非常简单的方法来创建流体和适应性布局。由于网格可以自动扩展以填充所有可用空间,因此它非常适合实现全屏 UI。网格布局允许您使用 CSS 完全对齐和定位其子元素作为列和行,与它们在 HTML 代码中的顺序无关。与使用浮动或脚本的方法相比,它使布局更加流体。

下面的例子演示了我们传统上如何使用浮动来定位元素:

以下是 HTML 代码:

<div class="container">
  <div class="leftDiv"></div>
  <div class="rightDiv"></div>
</div>

以下是 CSS 代码:

.container { width: 200px; height:50px; border: 1px solid black; }
.leftDiv { float:left; width: 100px; height:50px;background-color:blue}
.rightDiv { float:right; width: 50px; height:50px;background-color:red}

前面的代码将导致以下多色盒子。容器有一个黑色边框围绕着里面的两个 div,左边的蓝色 div 和右边的红色 div,之间的空白是剩余未占用的空间:

网格布局

网格布局通过将元素的display样式规则属性设置为-ms-grid来指定,或者您可以为内联级别网格元素使用-ms-inline-grid属性。您可能注意到了-ms这个厂商前缀(Microsoft-specific),这是因为这个 CSS 特性的状态仍然是一个工作草案;添加这个厂商前缀允许它在 Internet Explorer 10 和 Windows 8 中使用 JavaScript 构建的 Windows 商店应用中工作。以下是示例:

.divGrid {
  display: -ms-grid;
  -ms-grid-columns: 120px 1fr;
  -ms-grid-rows: 120px 1fr;
}
.column1row1 {
  -ms-grid-column: 1;
  -ms-grid-row: 1;
}
.column2row1 {
  -ms-grid-column: 2;
  -ms-grid-row: 1;
}

display: -ms-grid;属性创建了一个网格;之后,我们定义了列和行,并使用以下属性指定它们的大小:-ms-grid-column-ms-grid-row-ms-grid-columns属性指定了每列的宽度,而-ms-grid-rows指定了每行的 height, 在那个网格中。这两个属性中的宽度和高度值分别由一个空格字符分隔。在前面的例子中,-ms-grid-columns: 120px 1fr;属性创建了两个列;第一个宽度为 120 px,第二个宽度值为 1 fr,即一个分数单位,这意味着第二列的宽度将自动填充所有剩余的可用空间。行也适用同样的概念。在前面的代码片段中剩下的两个类将使用-ms-grid-column-ms-grid-row属性将具有这些类的元素定位到网格的列和行中。

注意

分数单位(fr) 表示可用空间应该如何根据它们的分数值在列或行之间进行划分。例如,如果我们有一个四列布局,如下所示:-ms-grid-columns: 100px 100px 1fr 2fr;,第 3 列占据一个分数,第 4 列占据两个分数的剩余空间。因此,剩余空间现在为 3 个分数;第 3 列被设置为 1 个分数除以总数(3),所以第 3 列和第 4 列(2 个分数)将分配剩余空间的三分之二。

在前面的示例中,我们使用了 px 和 fr 单位来指定列和行的尺寸。此外,我们还可以使用标准长度单位(如 px 或 em),或者元素的宽度和高度的百分比。还可以使用以下关键字:

  • auto: 这个关键字使得列或行的尺寸伸展以适应内部内容。

  • min-content: 这个关键字将列或行的尺寸设置为任何子元素的最小尺寸。

  • max-content: 这个关键字将列或行的尺寸设置为任何子元素的最大尺寸。

  • minmax(a,b): 这个关键字将列或行的尺寸设置为 a 和 b 之间的值,尽可能利用可用空间。

以下表格列出了与网格布局相关的属性:

-ms-grid-column 用于指定元素在网格中的列。编号系统是基于1 的索引类型。
-ms-grid-columns 用于指定每个网格列的宽度值。
-ms-grid-column-span 用于指定元素在网格中占据的列数。
-ms-grid-column-align 用于设置元素在列内的水平对齐值。
-ms-grid-row 用于指定元素在网格中的行。编号系统是基于 1 的索引类型。
-ms-grid-rows 用于指定每个网格行的宽度值。
-ms-grid-row-span 用于指定元素在网格中占据的行数。
-ms-grid-row-align 用于设置元素在行内的垂直对齐值。

此外,网格布局暴露出一组丰富的属性,使您能够轻松地适应用户界面的视图状态和应用程序的方向变化。我们将在设计应用程序时讨论这一点。

弹性盒布局(Flexbox layout)

我们拥有的第二种布局模型是 Flexbox 模式,这是 CSS3 中的又一次近期添加。与 Grid 布局类似,Flexbox 布局通过设置display属性启用,并且由于它仍是一个万维网联盟(W3C)工作草案,因此还需要一个微软特定的供应商前缀。Flexbox 布局用于使元素的相对位置和大体保持不变,即使屏幕和浏览器窗口的大小发生变化。与浮动相比,Flexbox 为元素的位置和大小提供了更好的控制。使用 Flexbox 布局的优势在于,它使元素在其内部具有相对定位和尺寸,因为它考虑了可用空间。这允许您创建一个流体布局,维持元素之间的相对位置和大小;因此,当浏览器或应用程序窗口的大小发生变化时,Flexbox 容器内的元素可以重新调整大小和位置。Flexbox 布局非常适合构建显示任何数字印刷媒体的应用程序,例如报纸或杂志。

与 Grid 布局一样,通过将display属性设置为-ms-flexbox,很容易创建一个带有 Flexbox 布局的容器。创建 Flexbox 容器后,我们可以开始使用以下属性操纵它内部的元素:

  • -ms-flex-direction:它使用以下关键字值指定子元素的取向:row(初始值)、columnrow-reversecolumn-reverse。我们将逐一介绍每个值,并展示它应用的效果,在下面的示例中。那么,更好的解释方法是什么呢?所以,假设我们有以下的 HTML 和 CSS 代码片段:

    <div class="flexit">
      <div>1</div>
      <div>2</div>
      <div>3</div>
    </div>
    
    .flexit {
      width:160px;
      height:100px;
      border:2px solid brown;
      display:-ms-flexbox;
      -ms-flex-direction: row;
    }
    .flexit div {
      background-color:red;
      width:50px;
      height:25px;
      text-align:center;
      color:white;
    }
    .flexit div:first-child {
      background-color:green;
      height:30px;
    }
    .flexit div:last-child {
      background-color:blue;
      height:30px;
    }
    

    前面的语法创建了一个带有flexit类的 Flexbox 容器,该容器以 Flexbox 布局包裹了标记有文本 1、2 和 3 的子<div>元素以进行跟踪。我们对一些子元素应用了一些样式和背景颜色。

    因此,在-ms-flex-direction属性中的以下值将给我们以下表格中的结果。注意元素的出现顺序和定位如何在不添加任何标记的情况下发生变化:

    属性 Flexbox 容器 元素的出现顺序和定位
    Flexbox 布局 子元素从左至右定位,与 HTML 标记中的出现顺序相同。
    行反转 Flexbox 布局 子元素从右至左定位,与 HTML 标记中的出现顺序相反。
    Flexbox 布局 子元素从上至下定位,与从左至右的 HTML 标记中的出现顺序相同。
    column-reverse Flexbox 布局 子元素从底部向上定位,按照 HTML 标记出现的顺序。
  • -ms-flex-align:此属性指定了 Flexbox 容器中子元素的对齐方式。它接受以下关键字值:startendcenterstretchbaseline。对齐总是垂直于在 -ms-flex-direction 属性中定义的布局轴;因此,如果方向是水平的话,它将对齐设置为垂直,反之亦然。例如,如果方向是 row(水平),则值 start 将设置对齐为顶部(垂直)。

  • -ms-flex-pack:此属性指定了如何将 Flexbox 容器中子元素之间的可用空间分配给定义在 -ms-flex-direction 属性中的轴线,与前面描述的对齐属性不同。它接受以下关键字值:startendcenterjustify

  • -ms-flex-wrap:此属性允许子元素溢出并在下一行或列中换行,并指定该流动的方向。它接受以下关键字值:nonewrapwrap-reverse

CSS 驱动的动画

CSS 转换 允许你以前只能通过脚本实现的方式来操作 HTML 元素。它使元素的旋转、平移、缩放和倾斜成为可能,并允许在 2D 和 3D 中转换元素。CSS 动画使你能够在一段时间内平滑地改变样式属性,与基于 JavaScript 的动画相比,使你能够设计出复杂动画且具有更好的渲染性能。将两者结合使用,你可以在应用上施展魔法。

CSS3 动画

CSS3 革命化了网页开发中的动画效果。在此之前,制作动画需要使用动画图片、Flash 这类插件,或者进行一些复杂的脚本编程。尽管 jQuery 和其他支持库让开发者用 JavaScript 制作动画变得稍微容易一些,但它在性能上仍然无法与 CSS 动画相匹敌。基本来说,动画定义了一个效果,允许元素在一段时间内改变一种或多种样式,如颜色、大小、位置、透明度等。此外,借助 CSS3 动画,你可以在动画过程中允许多种中间样式的变化,而不仅仅是动画开始和结束时指定的那些。

为了创建一个动画,你需要使用 @keyframe CSS 规则,该规则用于指定动画过程中将发生变化的样式。以下代码片段创建了一个名为 demo@keyframe 规则,将背景颜色从红色变为黄色,在中间 50% 的地方,将透明度变为零:

@keyframes demo {
  from { background: red;    }
  50% { opacity: 0;         }
  to { background: yellow; }
}

之后,我们将在@keyframe规则中定义的动画绑定到我们想要应用效果的元素(或选择器)上。如果动画不绑定到任何元素,它将不会在任何地方应用。在将动画绑定到选择器时,我们需要指定至少两个动画属性:

  • 名称

  • 持续时间

例如:

#logo { animation: demo 4s }

前面的示例将我们使用@keyframe规则创建的名为demo的动画,持续时间为 4 秒,绑定到 ID 为#logo的元素上。

动画一旦在 DOM 中定义,就会自动触发。你可以指定一定的延迟时间来避免这种情况,或者可以通过代码来触发动画。动画有以下六个主要属性,如下所示:

div {
  animation-name: demo;
  animation-duration: 3s;
  animation-timing-function: ease-in;
  animation-delay: 3s;
  animation-iteration-count: 2;
  animation-direction: normal;
}

或者我们可以使用动画简写属性,通过这个属性,我们可以将这些属性组合到一行中:

div { animation: demo 3s ease-in 3s 2 normal; }

由于浏览器支持问题,开发者仍然对使用 CSS3 动画或其他 HTML5 特性持谨慎态度。为了解决浏览器兼容性问题,一些样式规则必须定义带有厂商前缀的版本。例如,一个动画定义将被复制以支持其他浏览器,每个浏览器都有它自己的厂商前缀,如下所示:

-webkit-animation: 5s linear 2s infinite alternate;
-moz-animation: 5s linear 2s infinite alternate;
-o-animation: 5s linear 2s infinite alternate;
animation: 5s linear 2s infinite alternate;

但是在为 Windows 8 开发时,你可以将其减少到只有一个,这就是标准。担心多浏览器支持是最不需要担心的问题,因为 Windows 8 支持所有对 Internet Explorer 10 有效的标准。

CSS3 转换

CSS3 的另一个优点是 2D 和 3D 转换的概念,它使你能够以使用 CSS 无法实现的方式操纵应用中的元素。它使你能够在 2D 和全新的 3D 空间中对 HTML 元素进行旋转、缩放、倾斜和翻译,而无需插件或脚本,这是由 W3C 在CSS 转换规范下定义的。

使用transform属性创建转换,该属性包含一个或多个(由空格分隔)的转换函数,应用于指定的元素。属性值可以设置为一个或多个(由空格分隔)的转换函数,它们将按照列表的顺序应用。以下是一个示例代码,应用了旋转函数的transform属性:

div { transform: rotate(90deg) translateX(100px); }

前面transform属性的结果是,元素首先旋转 90 度,然后(水平)向右移动 100 像素。

transform属性可用的函数列表包括matrix()matrix3d()perspective()rotate()rotate3d()rotateX()rotateY()rotateZ()scale()scale3d()scaleX()scaleY()scaleZ()skew()skewX()skewY()translate()translate3d()translateX()translateY()translateZ()。这些函数在 Visual Studio 的 CSS3 智能感知功能中提供,因此,在编写transform属性时,你会被提示选择其中一个函数。

提示

Visual Studio 2012 通过提供如 Regions、IntelliSense、供应商前缀和内置片段等特性,增强了对 CSS 的支持,从而使得使用 HTML5 和 CSS 开发 Windows 8 应用变得非常简单和方便。

介绍媒体查询

你的 Windows 8 应用应该具有流畅和响应式的用户界面,因为同一个应用将会在平板电脑、带有大型显示器的 PC 或手机上下载和打开。你的应用应该适应不同的视图状态(全屏纵向或横向、填充或吸附),并相应显示。当用户在纵向和横向之间翻转屏幕、缩放、吸附应用时,应用应该看起来不错且功能良好。要关注的东西太多,你可能会说?不用担心,因为如果你正在使用 JavaScript 应用进行开发,所有你的担忧的答案就是CSS 媒体查询

通过使用 CSS 媒体查询,你可以通过轻松定义不同的样式来管理当前媒体的大小和视图状态对布局的影响,这些样式将应用于你的应用中的 HTML 元素。你可以为每个视图状态定义一个单独的媒体查询,或者可以将媒体查询组合起来,将同一组样式应用于多个视图状态。媒体查询的基本语法如下:

@media MediaType TargetMediaProperty{MediaRule}

它是一个逻辑表达式,要么是 true,要么是 false,并且由以下内容组成:

  • @media:这是一个指示媒体查询的关键字。

  • 媒体类型:它用于指定我们正在针对的媒体类型,可以有以下值之一:screen 用于计算机屏幕,print 用于以打印模式查看的文档,all 用于所有设备。

  • 目标媒体属性:通过添加如方向和大小等条件,它用于创建更具体的查询。

  • 媒体规则:它用于指定在媒体查询评估为 true 时将应用的一个或多个样式规则。

一个简单的例子如下:

@media screen and (max-width: 1024px) {
  body { 
    background-color: orange;
  }
}

前面的媒体查询将检查媒体是否是屏幕,且窗口的宽度不超过 400 像素。如果是 true,它将把橙色背景颜色应用到 body 元素上。

以下代码片段检查方向:

@media all and (orientation: portrait) {
...
}

我们还可以包含 Microsoft 特定的供应商属性 -ms-view-state 以检查应用可以处理的不同的视图状态。例如:

@media all and (-ms-view-state: snapped) {
...
}

总结

在本章中,我们尝试涵盖并从新的丰富的 CSS3 特性中学到尽可能多的内容,并描述在开发 Windows 8 应用时哪些是可用的。我们详细地查看了 CSS 选择器,并学会了根据我们的需要使用它们来过滤 DOM 元素。我们学习了使用 Grid 和 Flexbox 显示属性的新布局技术。

我们看到了动画和变换属性所能带来的魔法,也初步了解了媒体查询的强大,它能帮助我们构建响应式布局。简而言之,CSS3 就是一个奇妙的领域,你需要熟悉其特性才能充分利用它的力量。

在下一章,我们将学习 Windows 库为 JavaScript 提供的主要功能,这是使用 JavaScript 构建的 Windows 商店应用的骨架。

第三章: Windows 应用的 JavaScript

在本章中,我们将介绍由微软引入的Windows 库 for JavaScript(简称WinJS库)提供的一些功能,该库用于通过 JavaScript 访问 Windows 运行时,以便为 Windows 商店应用提供支持。Windows 库 for JavaScript 是一个 CSS 和 JavaScript 文件的库。它包含一组强大且功能丰富的 JavaScript 对象、函数和方法,这些对象、函数和方法按命名空间组织,旨在使开发人员更容易使用 JavaScript 创建 Windows 商店应用。

我们还将学习关于WinJS的异步编程,并了解我们如何可以使用WinJS.Utilities命名空间提供的函数查询文档中的元素并操作这些元素。接下来,我们将学习xhr函数及其使用,最后介绍由 Windows 库 for JavaScript 提供的一组 UI 控件。

使用 Promise 对象的异步编程

当构建一个 Windows 8 应用时,重点是拥有一个响应式 UI,这是 Windows 8 商店应用的主要特点之一。在第二章使用 CSS3 进行样式设计中,我们看到了我们如何在样式级别实现这一点。响应式 UI 还包括具有响应式功能,后台运行的代码不仅会突然阻塞应用的 UI,而且会使它在执行某些逻辑或功能时对任何用户输入不作出响应。

JavaScript 作为一种编程语言是单线程的,这意味着一个长时间运行的同步执行过程将阻塞所有其他执行,直到该过程完成。因此,你应该尽可能避免同步执行。这个困境的解决方案是异步处理,这对于创建响应式、高性能的应用程序至关重要。实现异步处理的一种方式是使用回调函数机制。回调函数用作一个钩子点,在之前的异步操作终止后继续处理。一个典型的例子是对服务器端后端的调用。

//code sample using jQuery
function longRunningComputation(callbackFunc){
    setTimeout(function(){
        //computation
       //once finished, invoke the callback with the result
       callbackFunc(computationResult);
    }, 1000);
}

这个函数然后按照如下方式调用:

longRunningComputation(function(compResult) {
    //do something meaningful with the result

});

回调函数是异步调用的典型解决方案,但它们有一个缺点:它们创建了深层链,特别是在你将多个异步操作放在一个链中,而后续函数又依赖于前一个计算结果时。Windows 库 for JavaScript 以及 Windows 运行时提供了一个更优雅的解决方案,使用了一种名为Promise的机制,它简化了异步编程。Promise,正如它的名字所暗示的,表示将来会发生一些事情,当这些事情完成后,Promise 就被认为是得到了满足。

在下面的代码示例中,我们创建了一个名为sumAsync的函数,它将返回一个WinJS.Promise对象,并在我们其在clickMe()函数中调用它时异步执行:

function clickMe() {
   sumAsync().then(
        function complete(result) {
            document.getElementById("result").textContent = "The promise has completed, with the result: " + result;
        },
        function error(result) {
            document.getElementById("result").innerHTML = "An Error has occurred </br>" + result;
        },
        function progress(result) {
            document.getElementById("result").innerHTML += "The promise is in progress, hold on please." + result;
        })
}
function sumAsync() {
    return new WinJS.Promise(function (comp, err, prog) {
        setTimeout(function () {
            try {
                var sum = 3 + 4;
                var i;
                for (i = 1; i < 100; i++) {
                    prog(i);
                }
                comp(sum);
            } catch (e) {
                err(e);
            }
        }, 1000);
    });
}

从前面的代码示例中我们可以推断出,Promise基本上是一个对象。这个对象实现了一个名为then的方法,该方法又采取了以下三个函数作为参数:

  • 一个在Promise对象完成并成功满足时会被调用的函数

  • 一个在Promise对象被满足时会调用的函数,称为未来

  • 一个在Promise被满足时会被调用的函数,以指示进度信息,称为延迟

在 Visual Studio 中,当你向一个函数添加一个then方法时,你将在 IntelliSense 弹出窗口中提示输入这些参数,如下面的屏幕截图所示:

使用 Promise 对象的异步编程

你可以使用then方法与任何返回Promise的函数;因为它返回Promise,所以你可以链接多个then函数。例如:

sumAsync() 
  .then(function () { return XAsync(); })
  .then(function () { return YAsync(); })
  .done(function () {  endProcessing();})

在前一个示例中,我们将多个then方法附加到函数上,并使用done方法完成处理。

注意

done方法接受与then相同的参数。然而,两者的区别在于done返回undefined而不是Promise,所以你不能链接它。此外,done方法如果在处理过程中没有提供error函数来处理任何错误,将抛出一个异常,而then函数不会抛出异常,而是返回error状态的Promise对象。

所有向 Windows Store 应用公开的 Windows 运行时 API 都被包装在Promise对象中,暴露出返回Promise对象的方法和函数,允许你在应用中轻松实现异步过程。

使用 WinJS.Utilities 查询 DOM

应用的界面由 HTML 和相应的样式描述。当应用启动时,你应该期待与界面不同的用户交互。用户将触摸应用的某些部分;他会滚动、缩放或添加/删除项目。此外,应用可能通过对话框或会话与用户交互,并通过在屏幕上发布通知来与用户交互。处理这些交互由代码完成,在我们的案例中,特别是由 JavaScript 代码完成。这时WinJS.Utilities就派上用场了,它提供了助手函数来完成这些任务;例如,添加/删除 CSS 类或插入 HTML 元素的功能。但在任何与用户交互之前,你必须使用 JavaScript 选择函数,这称为查询 DOM

In Chapter 2, Styling with CSS3, we saw how to select parts of the DOM using CSS selectors. JavaScript has built-in functions to do so by using the traditional document.getElementById function. This function has a limited functionality and does not allow selecting from the DOM using the CSS selector syntax as the jQuery selectors do, however, now JavaScript includes querySelector() and querySelectorAll(). These two functions are more powerful and take CSS queries just as the jQuery selector syntax does. While the querySelector() function returns a single DOM element, the querySelectorAll() function returns a list of nodes. Both functions exist on the document and element objects. So, you can query the document to find all matching results in the entire document, or you can just query a single element to find all matching objects under it. For example:

var postDiv = document.querySelector('#postDiv);
var allDivs = postDiv.querySelectorAll('div');

alongside these two JavaScript selection methods, the WinJS.Utilities namespace provides two functions with similar features for selecting elements, namely id() and query(). Basically, these functions wrap the querySelector and querySelectorAll functions but the return result value is different. The selector functions provided by WinJS.Utilities return a QueryCollection object, which in turn exposes various operations that perform actions over the elements of the collection, such as adding and removing a class and others.

The following code shows the syntax for using id() and query(). We first create a WinJS.Utilities object and call these two methods on it as shown:

var utils = WinJS.Utilities; 
var postDiv = utils.id('postDiv');  
var allParagraphs = utils.query('p');
allParagraphs.setStyle("color", "red");

The following screenshot shows the IntelliSense window that lists the functions provided by the WinJS.Utilities namespace:

Querying the DOM with WinJS.Utilities

Querying the DOM is also useful when you need to apply a behavior to the elements of document. For example, you might want to add a functionality whenever the user clicks on a particular button. We do so by first querying for that element and then adding a click handler to it. The following code shows how:

  WinJS.Utilities.id("Btn").listen("click", function () {
    var p = document.createElement("p");
    p.innerHTML = "i was just added";
    document.querySelector("#postDiv").appendChild(p);
});

In the previous code sample, the listen() method is used to wire an event handler to the click event of the button with the ID Btn; in this handler, we are creating a new p element and adding it to the div element with the ID postDiv.

Note

The methods provided by the WinJS.Utilities namespace are like a simplified subset of the functions provided in jQuery.

The following is a list of some of the available methods that you can call on the objects returned in QueryCollection:

  • addClass

  • clearStyle

  • getAttribute

  • hasClass

  • query(query)

  • removeClass

  • removeEventListener

  • setAttribute

  • setStyle

  • toggleClass

  • children

Understanding WinJS.xhr

The xhr function basically wraps the calls to XMLHttpRequest in a Promise object. The function is useful for cross-domain and intranet requests, as shown in the following code:

  WinJS.xhr(options).then(
     function completed(result) {
….
      },
     function error(result) {
….
      },
     function progress(result) {
….
      },

由于WinJS.xhr函数异步处理并返回一个Promise对象,我们可以像 previous example 中所示,向它传递then()done()方法。

你可以使用WinJs.xhr函数来连接 Web 服务并下载不同类型的内容,如文本或指定在WinJS.xhrresponseType选项中的 JSON 字符串。responseType选项取一个字符串值,指定从请求中期望的响应类型,类型如下:

  • text:这是默认值,期待一个字符串类型的响应。

  • arraybuffer:这期待一个用于表示二进制内容,如整数或浮点数数组的ArrayBuffer

  • blob:这期待一个BlobBinary Large Object),它是一个代表不可变原始数据的对象,通常文件大小较大。

  • document:这期待 XML 内容;也就是说,内容具有text/xmlMIME 类型的内容。

  • json:这期待一个 JSON 字符串

  • ms-stream:这期待一个处理流数据的msStream对象,并用供应商特定的前缀(ms)标记,因为它尚未在 W3C 规范中定义。

除了responseType,还可以在xhrXMLHttpRequest)对象上应用几个更多选项,这些都是可选的,除了url。这些选项如下:

  • url:这指定了一个字符串,它或者是 XML 数据或服务器端 XML Web 服务的绝对或相对 URL。

  • type:这指定了一个代表使用的 HTTP 方法的 string,例如GETPOSTHEAD

  • user:这指定了一个代表用于身份验证的用户名的字符串,如果需要的话。

  • password:这指定了一个代表用于身份验证的密码的字符串,如果有的话。

  • headers:这指定了一个代表自定义 HTTP 头的对象。

  • data:这指定了一个包含将通过 HTTP 请求发送到服务器的数据的对象;这些数据直接传递给XMLHttpRequest.send方法。

  • customRequestInitializer:这指定了一个可以在XMLHttpRequest上用于预处理的函数。

让我们填充以下代码中如何从网站上检索一些文本的基本语法:

WinJS.xhr(
{ url: 'http://www.msdn.microsoft.com/library', responseType: 'text' })
.done(function (request) 
{
    var text = request.responseText;
    document.getElementById("responseDiv").innerHTML = text;
},
function error(request) {
  var errorStatus = "Error returned: " + request.statusText;
  document.getElementById("errorDiv").innerHTML = errorStatus;
});

之前的代码示例将从一个指定的url字符串检索文本,并将其插入到div元素中,responseDiv;如果在处理过程中出现错误,我们通过statusText在错误处理函数中检索它。

注意

不建议使用XMLHttpRequest对象来请求可能需要很长时间才能完成的极其大型对象的传输,例如BlobFormData对象。相反,你应该考虑使用 Windows 运行时 API 提供的文件上传 API 来进行此类操作。

引入一组新的控件

除了内容,您的应用程序还需要控件;常规的 HTML 控件,如按钮、选择列表和复选框;以及一些 Windows 8 独有的控件,如 AppBar 评分和设置。除了标准的内置 HTML 控件外,WinJS还提供了一组新的、功能丰富的控件,这些控件是为使用 JavaScript 的 Windows 商店应用程序设计的。这些控件基本上是WinJS.UI命名空间中可用的对象;因此,日期选择器控件看起来像WinJS.UI.DatePicker。以下是您在应用程序中使用的主要的WinJS.UI控件列表:

  • DatePicker:用于选择日期值的定制控件。

  • TimePicker:用于选择时间值的定制控件。

  • Menu:用于显示命令的菜单弹出控制。

  • AppBar:用于显示命令的应用程序工具栏。

  • FlipView:用于一次性显示一系列项目的集合。

  • ListView:用于以可自定义的网格或列表布局显示项目的控件。

  • Flyout:这是一个轻量级的控件,用于显示包含信息的弹出式控件,但它不会像对话框那样创建一个单独的窗口。

  • Rating:这是一个允许用户评分并可以显示三种类型评分—临时、平均或用户评分的控件。

  • SemanticZoom:这是一个可以让用户在缩放视图和放大视图之间缩放的控件,由两个提供每种视图的单独子控件提供:

  • ToggleSwitch:这是一个可以让用户在两个状态之间切换选项(开和关)的控制。

  • Tooltip:用于显示有关对象的弹出式控件,其中包含有关对象的更多信息,并支持丰富的内容(如图像)。

  • ViewBox:这是一个缩放其包含的单个子元素(不改变其宽高比)的控制,使其适合并填充可用空间。

    注意

    这些控件会自动使用 Visual Studio 中创建的任何新的 Windows 8 商店应用程序项目中默认出现的两个样式表之一进行样式设计。这两个样式表(一个为深色主题,另一个为浅色主题)将给您的应用程序带来 Windows 8 的外观和感觉。

与标准的 HTML 控件不同,WinJS.UI控件没有专用的标记元素或属性标签;例如,您不能像正常添加标准 HTML 元素(如<input/>)那样,继续向您的标记中添加WinJS.UI.Rating元素(如<rating/>)。要添加一个WinJS.UI控件,您需要创建一个 HTML 元素,比如div,并使用data-win-control属性来指定您想要的控件类型。下面的代码显示了创建一个WinJS.UI Rating控件的语法:

<div id="ratingControlDiv" data-win-control="WinJS.UI.Rating"> </div>

这将声明一个评分元素在标记中,但当你运行应用程序时,不会加载控件。为了激活你在标记中声明的任何WinJS控件,必须调用处理文档并初始化你创建的控件的WinJS.UI.processAll()函数。当你使用 Visual Studio 提供的任何模板创建应用程序时,default.js文件中在app.onactivated事件处理程序中包含了对WinJS.UI.processAll的调用。

当你运行应用程序时,你会看到如下的新Rating控件:

介绍一组新的控件

你也可以通过调用其构造函数并在构造函数中传递将托管此控件的 HTML 元素来在代码中创建WinJS控件。例如,如果我们有一个div元素,其id属性为ratingControlDiv,创建Rating控件的 JavaScript 将如下所示:

var ratingHost = document.getElementById("ratingControlDiv");
var ratingControl = new WinJS.UI.Rating(hostElement);

在这种情况下,将无需调用WinJS.UI.processAll函数,因为你没有在标记中创建 JavaScript 控件。

此外,设置WinJS控件的属性与设置标准 HTML 控件的属性不同;后者有专门用于此目的的属性。例如,类型为rangeinput元素有minmax属性,其值可以在标记中如以下代码所示设置:

<input type="range" min="2" max="10" />

对于 JavaScript 控件,我们必须在标记中使用data-win-options属性来设置属性,它是一个包含一个或多个属性/值对的字符串(多个属性以逗号分隔),在基本形式下如以下代码所示:

data-win-options="{propertyName: propertyValue}"

下面的语法将显示如何为WinJS.UI.Rating控件设置minRatingmaxRating属性:

<div id="ratingHostDiv" data-win-control="WinJS.UI.Rating"
    data-win-options="{ minRating: 2, maxRating: 10}"> 
</div>

总结

我们已经瞥见了WinJS在 Windows 8 中的某些功能和强大特性。我们学习了如何使用Promise对象实现异步编程。

此外,我们还介绍了WinJS.Utilities命名空间中提供的方法,这些方法允许我们检索和修改 HTML 文档的元素。我们还介绍了使用WinJS.xhr()函数检索不同类型内容的方法。

最后,我们学习了WinJS库提供的新一组控件以及如何创建这些 JavaScript 控件并设置它们的属性。

在下一章中,我们将开始使用 JavaScript 开发应用程序,首先介绍所需的工具,然后学习为 Windows 8 JavaScript 应用程序提供的模板。此外,我们将创建一个非常基础的应用程序,并了解 JavaScript 应用程序的解剖结构。我们还将学习 ListView 控件。

第四章:使用 JavaScript 开发应用程序

在本章中,我们将学习如何使用 JavaScript 开始开发 Windows 8 应用程序。首先,我们将学习有关工具的知识,然后我们将介绍如何获取开发者许可证。之后,我们将从为 Windows Store 应用程序开发提供的模板中选择一个,从一个空白模板构建一个示例应用程序,并对其进行修改,以便我们了解一些 JavaScript 应用程序的功能。

介绍工具

Windows 8 引入了一种新类型的应用程序——Windows Store 应用程序,这种应用程序只能在 Windows 8 上运行。所以,为了开始开发,你首先需要在你的电脑上安装 Windows 8,第二,你需要所需的开发工具。

获取 Windows 8 有两个选择;一种选择是从 MSDN 的订阅者下载处获取,如果你在那里有订阅的话。另一种选择是,如果你没有 MSDN 账户,你可以从通过 MSDN 网站上的msdn.microsoft.com/en-US/evalcenter/jj554510.aspx?wt.mc_id=MEC_132_1_4找到的评估中心获取 Windows 8 企业版的 90 天评估版本。

注意

请注意,评估版在过期后无法升级。

在安装 Windows 8 之后,你需要下载开发工具,这些工具在 MSDN 网站上免费提供,可以在msdn.microsoft.com/en-US/windows/apps/br229516.aspxWindows 开发者中心页面找到。Windows 开发者中心拥有全新的改进布局,是你获取所有工具和资源的首个起点,可以在Windows Store 应用程序开发下载部分找到。

必要的下载是包含 Visual Studio Express 的捆绑包,这将是你开发 Windows 应用程序的工具。这个下载的链接可以在Windows 8 的 Visual Studio Express 2012部分找到,并包括以下文件:

  • 微软视觉工作室 Express 2012 for Windows 8

  • 微软视觉工作室 2012 的 Blend

  • Windows 8 软件开发工具包(SDK)

  • Windows Store 应用程序项目模板(在微软视觉工作室 2012 中提供)

此外,你还可以在该页面上找到其他可用的下载,例如:

  • 设计资源:这包括必要的 Photoshop 模板(.psd文件),其中包括模板、常用控件和常见组件,如合同、通知和磁贴,这些是设计应用程序所需的。

  • 示例应用程序包:这包括数百个来自微软的代码示例,可以帮助你快速启动项目并了解大部分功能。这适用于所有或特定编程语言。

  • Windows 8 动手实验室:这包括一系列八个动手实验室模块,这些模块将引导您开发一个名为 Contoso Cookbook 的 Windows Store 应用。这包含了 Windows 8 中许多关键的新功能。这些实验室系列可通过 JavaScript 和 HTML,或 C#和可扩展应用程序标记语言XAML)获得。

  • Live SDK:这包括一组控件和 API,我们可以使用它们来使应用与 Microsoft 账户集成单点登录SSO),并访问来自 SkyDrive、Hotmail 和 Windows Live Messenger 的信息。

    注意

    由于 Visual Studio 2012 仅支持 Windows 8 的 Windows Store 应用开发,因此即使安装了 Visual Studio 2012,您也无法在 Windows 7 上开发应用。而且,由于没有为 Windows Server 2012 提供开发者许可证,所以您也无法在 Windows Server 2012 上开发 Windows Store 应用。

    请注意,您可以使用 Visual Studio 2012 的其他任何版本来开发 Windows Store 应用,包括 Ultimate、Premium、Professional 和 Test Professional 版本。

获取免费开发者许可证

为了开始开发 Windows Store 应用,您需要拥有 Windows 8 的开发者许可证。这个许可证允许您在 Windows Store 测试和认证之前,在本地安装、开发、测试和评估应用。此外,开发者许可证是免费的,您不需要 Store 账户就可以获得一个;它只需要一个 Microsoft 账户,并且每个账户可以获取多个许可证。许可证在 30 天后过期,必须续订。如果您已经有了一个 Windows Store 账户,许可证将为您提供 90 天服务。在您在本地计算机上获得许可证之后,除非许可证过期或您删除它(可能通过格式化或卸载 Visual Studio),否则在该计算机上不会再提示您。获得一个许可证非常简单;您可以使用 Visual Studio 2012 来获取开发者许可证。当您第一次在 Windows 8 上运行它时,它会提示您获得一个开发者许可证;您只需要使用您的 Microsoft 账户登录即可。您总是可以尝试通过使用 Visual Studio 中的商店选项来获取或续订 Windows 8 的开发者许可证,我们将在第十章 打包和发布 中详细讨论打包和发布应用时,学习如何发布应用。

注意

请记住,如果您还没有这样做,第一次尝试运行应用时将被提示获取开发者许可证。

下面的屏幕截图显示了使用 Visual Studio 2012 Ultimate 的过程。请前往项目 | 商店 | 获取开发者许可证

获取免费开发者许可证

如果您使用的是 Express 版,您将在顶部菜单中直接有一个商店选项,而不是在项目下面。您只需前往商店 | 获取开发者许可证

注意

选择不获取或续签开发者许可证,当你尝试在 Visual Studio 中构建或部署应用时,将会导致错误(代码 DEP0100)。

安装 Windows 8 和所需工具并获得开发者许可证后,您就可以开始构建您的第一个应用了。您开始时需要选择一种编程语言来使用。如我们之前提到的,Windows 8 允许您基于您的编程语言知识库进行构建,并用您已经知道的编程语言进行开发(除非您想学习新东西)。如果您从事网页开发,可以选择 JavaScript 作为您的编程语言,并使用最新的网页开发技术(例如 HTML5 和 CSS3),这本书就是关于这些内容。如果您来自.NET 背景,可以选择 Visual C#或 Visual Basic 和 XAML。您还有使用 C++选项,分别是 C++和 XAML,或者 C++和 DirectX。

使用 Visual Studio 及其模板

所以现在我们有了工具。有了 Visual Studio 作为我们的游乐场和 JavaScript 作为我们的编程语言,我们已经准备就绪可以开始开发了。我们将从为 Windows Store 创建一个新项目开始。点击文件 | 新建项目。向下钻取到已安装,然后到模板,再到JavaScript | Windows Store,并选择一个模板类型,如下面的屏幕截图所示:

使用 Visual Studio 及其模板

正如你在之前的屏幕截图中所看到的,在新建项目对话框的中心面板上有五种模板可供选择。这些模板随 Visual Studio 2012 提供,为您提供了良好的起点,并帮助您快速启动和加速应用的开发。这些项目模板,按照它们在新建项目对话框中出现的顺序,如下所示:

  • 空白应用:这是一个基本的工程项目模板,创建一个空的 Windows Store 应用,可以编译和运行。然而,它不包含任何用户界面控件或数据。

  • 网格应用:这是一个提供网格视图格式的内容的工程项目。它是允许用户浏览数据类别以查找内容的应用程序的良好起点。其使用的一些例子包括 RSS 阅读器、购物应用、新闻应用和媒体画廊应用。

  • 分割应用:这是一个提供内容分割视图的项目,其中数据以两栏的主/详细视图显示,列表数据在一侧,每个单一数据项的详细信息在另一侧,就像 Outlook 一样。其使用的一些例子包括新闻阅读器应用、体育比分应用和电子邮件应用。

  • 固定布局应用:这是一个基本且最小的模板项目,类似于使用空白应用模板创建的应用,不同之处在于此布局中的内容针对固定布局视口,即当窗口大小变化时容器会自动调整大小以适应显示区域;这种缩放是通过使用ViewBox控件来保证的。

  • 导航应用:这是一个创建采用单页导航模型(Windows Store 应用推荐使用)的项目。您不能仅通过在标记中添加锚点链接来实现导航模型;相反,导航模型是通过使用navigator.js文件来实现的,该文件也可以在网格和分屏模板中找到,而空白应用固定布局应用模板则不包含此文件,因此您必须手动添加该文件。

    注意

    网格应用分屏应用模板不仅是一个构建应用程序的好起点,而且也是很好的学习模板,能让您对应用程序是如何构建的以及它由什么组成有一个很好的了解。

三个模板空白应用网格应用分屏应用可供 Windows Store 开发中所有可用的编程语言使用。每个项目模板都包含了实现它所代表功能的必要文件,无需您进行任何开发;例如,创建一个新的网格应用并运行它,将会得到如下应用程序:

使用 Visual Studio 及其模板

结果是一个准备好用于 Windows Store 的应用程序,其中包含带有启用导航的示例数据,甚至支持粘贴和填充布局,这是当分辨率在并排的两个应用程序之间分配时应用程序存在的布局。所有这一切甚至不需要编写一行代码!所以,想象一下,如果您通过为布局应用不同的样式并在内容中显示真实数据(比如说,新闻网站的 RSS 源),对这个最小化的应用进行一些定制,您将很快拥有一个超过 75%准备好上架的应用程序(还缺少一些功能,比如语义缩放、应用栏和设置)。

您还可以直接从 Visual Studio 下载示例。这些示例提供了完整且可运行的代码示例,可以编译并作为 Windows Store 应用运行,旨在展示 Windows 8 中可用的各种新的编程模型、平台、功能和组件。

项目项模板

除了项目模板之外,还有特定于 Windows Store 应用的语言项模板,在我们的案例中,称为JavaScript 项模板。这些项模板是可以添加到已存在项目中的应用程序文件,包含常用的代码和功能(可以把它看作是一个用户控件),并且有助于减少开发时间。可以通过右键点击顶部菜单中的项目,然后选择添加 | 新建项,来添加项模板。有四个 JavaScript 项模板可供使用;它们如下所示:

  • 页面控制:这包含了应用程序中页面的基本内容和标记。其中包括一个带有返回按钮的头部区域和一个主要内容区域。每个页面控制模板将包括三个要添加到项目的文件(一个包含所需标记的 HTML 文件,一个包含与页面相关的代码的 JavaScript 文件,以及一个为页面提供特定样式的 CSS 文件)。

  • 文件打开选择器合同:这将添加一个功能,使应用程序能够使用文件选择器对话框将其数据作为文件列表提供给其他请求文件的应用程序。它还将文件显示在 ListView 控件中。这个合同的一个典型用途是在创建一个照片选择器对话框时。

  • 搜索合同:这将添加一个允许应用程序响应来自 Windows 8 中搜索磁贴的搜索查询的搜索合同。它包含一个搜索结果页面,用于向用户展示结果。如果您的应用程序有一些可以搜索的数据,添加这个合同是很重要的。

  • 分享目标合同:这将向应用程序添加一个分享合同,允许应用程序与其他应用程序共享数据,并使其与 Windows 8 中的分享磁贴集成。所以,如果应用程序具有此合同,它将出现在分享 UI 中的应用程序列表中。这个模板的典型用途是允许用户将链接或照片发布到 Facebook,Twitter 或任何其他接收共享内容的其他应用程序。反之亦然,它还将允许应用程序接收共享内容;因此,应用程序可以表现得像 Facebook 或 Twitter。

下面的屏幕截图显示了带有前面列出的项目模板的添加新项对话框:

项目模板

注意

我建议您将每个项目模板添加到单独的文件夹中,并且文件夹名称与其相关联。由于每个项目模板都增加了三个相关文件,如果您将它们分组到单独的文件夹中,解决方案将更加整洁和有序。例如,为页面创建一个文件夹,并在其中为每个页面创建一个文件夹;合同部分也是如此。

选择一个应用程序模板并将其加载到 Visual Studio 之后,您基本上已经创建了一个非常简单的应用程序;这个应用程序可以直接编译和运行。使用 Visual Studio,您可以在本地计算机或模拟器上运行应用程序。要在本地计算机上运行它,只需按F5键来构建,部署并启动应用程序。

注意

请注意,您可以选择不部署解决方案,但是应用程序不能直接运行;您需要从开始菜单中的其他应用程序中找到它,然后手动启动它。

还有一种通过以太网电缆直接连接远程设备运行的方法。要使用模拟器,您只需要从运行菜单中选择以下屏幕截图所示的选项:

项目模板

Windows 8 模拟器是一个极好的工具,能帮助你测试和调试应用;它允许你像在真实设备上一样测试功能,特别是如果你在开发过程中没有平板电脑或触控设备。它能让应用在横屏和竖屏之间改变分辨率,并在不同的应用布局和视图状态(嵌入式和全屏)之间切换。此外,你还可以测试应用对触摸和手势(如滑动和捏合缩放)的响应。在开发过程中,我们无法在笔记本电脑或 PC 上尝试所有这些功能和特性。

注意

当你在 Visual Studio 中以调试模式运行应用时,你可以更改代码和标记,并刷新应用以查看更改,而无需重新构建/重新运行。你可以使用刷新 Windows 应用按钮来实现,该按钮将在暂停、停止和重新启动调试按钮旁边出现,仅在你从 Visual Studio 中运行应用后出现。

开始使用空白应用

让我们使用空白应用模板开始创建一个最小应用;我们首先需要做的是启动 Visual Studio 2012,创建一个新项目,并前往JavaScript | Windows Store | 空白应用。尽管空白应用在运行时看起来很空,但它包含了一些使用 JavaScript 创建的 Windows Store 应用所需的文件;其他所有模板都将包含这些文件。以下屏幕截图显示了此应用在解决方案资源管理器窗口中的结构:

开始使用空白应用

此前的屏幕截图展示了简单应用的骨架,包括以下文件:

  • Windows Library for JavaScript 1.0:Windows Library for JavaScript 是一个 CSS 和 JavaScript 文件的库。当你深入这个文件夹时,你会看到它包含两个子文件夹,如下所示:

    • css:此文件夹包括两个主要的 CSS 样式表,它们是ui-dark.cssui-light.css,这些样式表为应用提供了 Windows 8 的外观和感觉。正如它们的名称所暗示的,第一个将应用一个深色主题,而第二个将应用一个浅色主题。你可以在 HTML 页面中引用其中的一个来选择。

    • js:此文件夹包括base.jsui.js;这两个文件包含了提供控件、对象和帮助函数的 JavaScript API,所有这些都组织成名称空间,这将使使用 JavaScript 的开发体验变得更加容易。

  • default.css:这是包含应用 CSS 样式的样式表。

  • images:此文件夹包含展示应用及其身份所需的图片(两个标志、启动屏幕图片和商店标志)。

  • default.js:此 JavaScript 文件实现了应用的主要功能,并包含了处理应用生命周期的代码。在这个文件中,你可以编写与default.html页面相关的任何附加代码。

  • default.html:这是应用程序的起始和主页,当应用程序运行时首先加载。它提供了内容宿主(主窗口中加载每个页面)的标记。

  • package.appxmanifest:这是清单文件。它基本上通过指定描述应用程序的属性,如名称、描述、起始页面等,来描述 Windows 上的应用程序包。

  • TestApp_TemporaryKey.pfxAppName_TemporaryKey.pfx):这个文件签署了.appxmanifest文件。

让我们来看一下default.html页面,这是应用程序的起始页面(在这个案例中,也是唯一页面):

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>TestApp</title>
    <!-- WinJS references -->
  <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
  <script src="img/base.js"></script>
  <script src="img/ui.js"></script>

  <!-- TestApp references -->
  <link href="/css/default.css" rel="stylesheet" />
  <script src="img/default.js"></script>
</head>
<body>
  <p>Content goes here</p>
</body>
</html>

Doctype html可以看出,页面是 HTML5 的。我们在<head>中放置了应用程序的标题,然后是 JavaScript(WinJS)文件的引用。引用用WinJS references注释标记。首先引用.css文件,这样脚本的加载就不会延迟或阻碍样式的加载,如果.js文件对样式表进行了某些修改,需要在加载样式之前加载样式。这里应用了深色主题;你可以简单地将其更改为浅色主题,通过如下更改引用:

<link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />

注意

不要修改WinJS的 CSS 和 JavaScript 文件。最好创建样式或 JavaScript 函数,在不同文件中覆盖现有的样式和功能,并将它们应用于应用程序。

WinJS引用下,有对应用程序特定的样式表和 JavaScript 文件的引用,这些引用通过注释清晰地区分。

然后是 body 部分。在这里,以空白应用程序为例,body 只包含简单文本。

如果你尝试以当前状态启动应用程序,你会看到屏幕上覆盖着黑色背景,还会看到文本:内容在此处。在这个页面出现之前,你会注意到一个启动屏幕出现几秒钟,显示在清单文件中指定的启动屏幕图像。让我们尝试通过修改我们的起始页面并向 body 添加一些标记,给这个空白应用程序带来一些生命,就像你之前处理过的任何 HTML 页面一样。

用以下内容替换现有的段落元素:

<body>
  <h1>The Test App</h1>
  <p>Add some content </p>
  <input id="contentInput" type="text" />
  <button id="sayButton">Have your say</button>
  <div id="contentOutput"></div>
</body>

运行应用程序;它将显示我们刚刚添加的标记。我们可以在input元素中输入任何文本,但点击按钮将没有效果。所以让我们为这个按钮创建一个事件处理程序,在div中输出我们在input元素中添加的内容。我们需要在default.js文件中创建事件处理程序,因为那里是我们编写与default.html页面交互的额外代码的地方。

首先让我们来看一下这个default.js文件。你会注意到里面有一些用单个函数包裹的代码,如下所示:

(function () {
   "use strict";
  …
})();

这段代码代表了一个自执行的匿名函数,它包含所有你的代码以避免任何命名冲突,并保持全局命名空间干净,没有不必要的标识符。匿名函数的第一行代码声明了关键字use strict,它为 JavaScript 代码开启了严格模式。这种严格模式提供了更好的错误检查,例如防止你给只读属性赋值。在这行之后,你会看到剩下的代码,它通过添加app.onactivatedapp.oncheckpoint事件处理程序来处理应用程序的激活和检查点状态。我们添加在app.onactivated事件处理程序内部的代码将在应用程序启动时添加。

现在回到按钮事件处理函数;我们创建一个如下函数:

function buttonClickHandler(eventInfo) { 
  var text = document.getElementById("contentInput").value; 
  var outputString = "I say " + text + "!";
  document.getElementById("contentOutput").innerText = outputString; 
}

在最底部的app.start()调用之前的匿名函数内部添加这个函数。这个函数从input元素中获取文本并将其添加到div元素中。为了将这个函数添加到按钮的事件中(在本例中,是onclick事件),我们需要为按钮注册一个事件处理程序。建议通过调用addEventListener方法来完成。当应用程序被激活时,我们需要注册这个事件处理程序。因此,我们应该在app.onactivated事件处理程序内部添加它。代码如下所示:

var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;

app.onactivated = function (args) {
  if (args.detail.kind === activation.ActivationKind.launch) {
       if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
      // TODO: This application has been newly launched. Initialize
         // your application here.
    } else {
  // TODO: This application has been reactivated from suspension.
  // Restore application state here.
     }
     args.setPromise(WinJS.UI.processAll());

     // Retrieve the button and register our event handler.
     var sayButton = document.getElementById("sayButton");
     sayButton.addEventListener("click", buttonClickHandler, false);
}
};

app变量是一个全局变量,代表提供应用程序级别功能的Application类的实例;例如,处理不同的应用程序事件,如我们之前代码列表中看到的onactivated事件。

onactivated处理程序内部,代码检查发生的是哪种类型的激活;在本例中,是启动激活,这意味着该应用程序在没有运行时被用户激活。然后调用WinJS.UI.processAll()。这将扫描default.html文件中是否有任何WinJS控件,并将初始化它们。由于按钮不是一个WinJS控件,而是一个基本的 HTML 控件,我们可以在调用WinJS.UI.processAll()之前添加它,但最好在之后注册事件处理程序。

运行应用程序,在文本框中输入一些文本,当点击按钮时显示内容,如下面的屏幕截图所示:

Blank App 入门

理解 ListView 控件

在上一章中,我们介绍了一个由 Windows 库为 JavaScript 提供的新控件集;这些控件中的一个是 ListView 控件,标记为WinJS.UI.ListView。这个对象的基本作用是显示可自定义的列表或网格中的数据项。要创建一个 ListView 控件,我们需要向div元素添加data-win-control属性,并将其属性设置为WinJS.UI.ListView。在default.html页面中,在body标签内部添加以下代码:

<body>
  <div id="sampleListView" data-win-control="WinJS.UI.ListView">
  </div>
</body>

这将创建一个空的 ListView。所以,如果我们运行该应用,将看不到任何东西。由于这是一个WinJS控件,它将在我们调用WinJS.UI.processAll函数后才在标记 up 中渲染。

让我们给sampleListView控件添加一些数据以显示。这些数据可能来自网络数据库或 JSON 数据源,将手动创建数据源,最好在单独的 JavaScript 文件中,这样更容易维护。所以,在 Visual Studio 中,在js文件夹下,添加一个新项目并选择一个 JavaScript 文件;将其命名为data.js。打开这个新创建的文件,创建一个带有严格模式的匿名函数,就像我们在default.js文件中看到的那样;在这个函数内部,让我们创建一个由对象组成的样本数组,这些对象构成了我们需要的数据源。给数组中的每个对象赋予三个属性firstNamelastNameAge

最终代码将如下所示:

(function () {
    "use strict";
    //create an array for a sample data source
    var dataArray = [
    { name: "John Doe", country: "England", age: "28" },
    { name: "Jane Doe", country: "England", age: "20" },
    { name: "Mark Wallace", country: "USA", age: "34" },
    { name: "Rami Rain", country: "Lebanon", age: "18" },
    { name: "Jean Trops", country: "France", age: "56" }

    ];

    //create a list object from the array
    var sampleDataList = new WinJS.Binding.List(dataArray);
})();

接下来,我们使用刚刚创建的数组来创建一个 List 对象;然后我们需要通过声明一个命名空间并将其作为公共成员添加来暴露这个 List 对象:

    // Create a namespace to make the data publicly
    // accessible. 
    var publicMembers =
        {
            itemList: sampleDataList
        };
    WinJS.Namespace.define("DataSample", publicMembers);

为了使 ListView 控件能够访问这个列表,我们使用了WinJS.Namespace.define函数来创建一个命名空间,并将列表作为其成员之一,从而使列表公开可用,因为它是匿名函数中创建的,这使其保持私有。WinJS.Namespace.define函数接受两个参数,正如你在之前的代码中注意到的那样。第一个参数是要创建的命名空间的名字,第二个参数表示包含一个或多个键/值对的对象(publicMembers)。

在创建数据源并使其被 ListView 控件访问后,下一步是将数据源连接到 ListView 控件。这必须在default.html文件中完成。让我们从我们留下的示例空白应用开始。我们需要添加对我们刚刚创建的数据文件的引用,如下所示:

<!-- Sample data file. -->
<script src="img/data.js"></script>

然后我们将data-win-options属性添加到div元素中,并使用我们在data.js中创建的数据源来设置data-win-options属性内的itemDataSource属性。将 ListView 控件的itemDataSource属性设置为DataSample.itemList.dataSource,如下所示:

<div id="sampleListView" data-win-control="WinJS.UI.ListView" 
 data-win-options="{ itemDataSource : DataSample.itemList.dataSource }">  
</div>

DataSample.itemList.dataSource命名空间包括DataSample,这是我们之前注册的命名空间;itemList,是我们注册在命名空间上的对象的属性名称;最后是dataSource,它是WinJS.Binding.List方法的一个属性(我们之所以能在itemList上调用它,是因为后者被分配给了我们从数组创建的 List 对象)。

如果我们现在运行该应用,我们会看到 ListView 控件以无格式的方式显示我们创建的数组,如下所示:

    { name: "John Doe", country: "England", age: "28" }
    { name: "Jane Doe", country: "England", age: "20" }
    { name: "Mark Wallace", country: "USA", age: "34" }
    { name: "Rami Rain", country: "Lebanon", age: "18" }
    { name: "Jean Trops", country: "France", age: "56" }

我们可以通过覆盖 Windows Library for JavaScript 中定义的win-listview类中的默认样式来样式化这个 ListView 控件,以样式化 ListView 控件。为了覆盖默认样式并将一些样式应用到此 ListView 控件上,请复制win-listview类并将其前缀与我们要创建的div元素的特定 ID 一起使用,如下所示:

#sampleListView.win-listview {
  width: 500px;
  border: 1px solid gray;
}

我们可以在 ListView 内部添加更多的样式,并且可以使用WinJS.Binding.Template定义项目模板,以定义我们要使用来显示每个列表项及其样式的标记。创建WinJS.Binding.Template控件非常简单;在 HTML 页面上,添加一个div元素并将数据属性data-win-control的属性设置为WinJS.Binding.Template。在其中,再添加一个将作为模板内容的父元素的div元素,因为WinJS.Binding.Template必须有一个单一的根元素。在这个父元素内部,我们添加将要创建的标记,ListView 将使用它来填充它包含的每个数据项。现在模板将看起来像这样:

<body>
<div id="sampleTemplate" data-win-control="WinJS.Binding.Template"> 
      <div style="width:200px; height: 100px">    
           <div>    
              <!-- Displays the "name" field. -->
              <h2> </h2>
              <!-- Displays the "country" field. -->
              <h3> </h3>
              <!-- Displays the "age" field. -->
              <h6 style="color:red"> </h6>
           </div>    
      </div>
</div>
</body>      

为了将每个元素链接到特定的数据项属性,我们在每个显示数据的元素上使用data-win-bind属性。data-win-bind属性使用此语法:data-win-bind="propertyName: dataFieldName"。因此,要设置h2h3h6元素上的 name 属性,我们使用以下代码:

<!-- Displays the "name" field. -->
<h2 data-win-bind="innerText: name"></h2>
<!-- Displays the "age" field. -->
<h3 data-win-bind="innerText: country"></h3>
<!-- Displays the "age" field. -->
<h6 style="color:red" data-win-bind="innerText: age"></h6>

请注意,列表项模板(WinJS.Binding.Template)在标记 up 中应该在 ListView 控件之前,仅仅是因为 HTML 标记是层次化的,每个 UI 元素都将按遇到它们的顺序进行渲染。因此,当 ListView 控件正在渲染并绑定到itemTemplate元素时,这个itemTemplate元素必须首先存在;否则它会抛出错误。

最后,我们需要将我们刚刚创建的绑定模板应用于 ListView 控件。因此,使用select语法将 ListView 的itemTemplate属性设置为sampleTemplate,如下所示:

<div id="sampleListView" data-win-control="WinJS.UI.ListView" 
data-win-options="{ itemDataSource : DataSample.itemList.dataSource, itemTemplate: select('#sampleTemplate') }">
</div>

如果我们现在运行该应用程序,ListView 控件将以一种更合适的方式显示数据。它看起来会是这样:

了解 ListView 控件

概要

在本章中,我们已经介绍了使用 JavaScript 创建 Windows Store 应用程序的基础知识。我们了解了工具,以及我们需要的开发入门知识。然后我们了解了如何使用 Visual Studio 2012,并查看了为使用 JavaScript 进行开发提供的模板。

我们了解了如何从零开始构建一个应用程序,在过程中我们看到了 JavaScript Windows Store 应用程序的解剖结构;我们将这个空白应用程序修改为以最简单的方式进行交互,只需点击一个按钮。最后,我们学习了如何使用 ListView 控件来显示数据。

在下一章中,我们将学习如何获取我们想要显示的数据。

第五章:绑定数据到应用

在本章中,我们将学习如何从不同的数据源实现数据绑定到应用中的元素。Windows 库为 JavaScript 提供了数据源对象,可以用来填充WinJS控件如ListViewFlipView的不同类型的数据。我们有WinJS.Binding.List对象,用于访问数组和 JSON 数据,还有StorageDataSource对象,提供对文件系统信息的访问。这两个数据源对象使我们能够查询并在数据源中绑定项目。此外,我们还将学习如何对数据源进行排序和筛选,并使用ListView控件显示其数据。

获取数据

Windows 库用于 JavaScript 绑定的WinJS.Binding)提供了一种将数据和样式绑定到 HTML 元素的方法。Windows 库提供的 JavaScript 绑定默认是单向的,所以当数据发生变化时,HTML 元素会被更新;然而,HTML 元素的任何变化都不会反映到绑定到的数据上。让我们通过实际操作来了解这一点,并且我们从最基本的绑定类型开始,即 HTML 元素与仅包含数据的简单 JavaScript 对象之间的声明性绑定。

首先,我们将检查WinJS.Binding.optimizeBindingReferences属性,如果尚未设置,则将其设置为true

提示

在执行声明性绑定时,始终设置WinJS.Binding.optimizeBindingReferences属性为true非常重要。此属性决定是否应自动为元素的 ID 设置绑定。在使用WinJS.Binding的应用程序中,应将此属性设置为true

我们将创建一个包含两个属性的 sample person JavaScript 对象,namebadgeColor,如下面的代码所示:

var person = { name: "John", badgeColor: "Blue"};

现在,我们将使用数据属性data-win-bind将 HTML span元素绑定到person对象,如下面的代码所示:

<span id="nameSpan" data-win-bind="innerText: name"></span>

为了使绑定发生并且随后在span元素中显示名称,我们必须调用WinJS.Binding.processAll()方法,并传递给它 DOM 元素和dataContext对象;它会从这个指定的元素开始寻找data-win-bind属性,然后遍历该元素的的所有后代。

以下代码从 DOM 中获取span元素,然后将参数传递给WinJS.Binding.processAll()方法:

var nameSpan = document.getElementById("nameSpan");
WinJS.Binding.processAll(nameSpan, person);

提示

如果你正在使用这个示例的 default.HTML 页面,你需要在调用args.setPromise(WinJS.UI.processAll())之后添加代码,以便所有控件都已初始化,如在第三章 JavaScript for Windows Apps中解释的那样。

运行项目后,你将在屏幕上看到John这个名字。前面的代码只实现了一个静态绑定,这意味着文本不会受到数据变化的影响。这是因为 JavaScript 对象本身无法通知应用程序当它发生变化。我们可以使用WinJS.Binding.as将这个对象变为可观察的对象,这将使得数据源在对象中的项发生变化时得到通知。以下代码片段将创建一个bindingSource对象,它表示我们创建的person对象的观测实例;因此,对bindingSource的任何更改都将反映在与它绑定的 HTML 元素上:

var bindingSource = WinJS.Binding.as(person);

让我们看看动态数据绑定的实际效果。首先,向输入姓名值和button元素的input type中添加代码,如下面的代码所示:

<input type="text" id="nameInpt" />
<button id="setNameBtn">Get name</button>

然后,我们编写模拟person数据对象变化的代码。我们通过在setNameBtn按钮的点击事件中设置person对象的name属性为在input元素中输入的新值来实现,如下面的代码所示:

document.getElementById("setNameBtn").onclick = function () {
  var newName = document.getElementById("nameInpt").value;
  bindingSource.name = newName;
}

运行项目,尝试在input元素中输入新值,然后点击按钮查看名称是否发生变化。

我们不仅可以将数据绑定到 HTML 元素上,还可以在样式级别应用绑定。回到上一个例子,让我们将style.background值添加到数据属性中,并绑定到person对象的badgeColor字段,如下面的代码所示:

data-win-bind="innerHTML: name; style.background: badgeColor"

做出上述更改后,刷新应用,名字将会用蓝色高亮显示。当你运行应用时,输出应该看起来像下面的截图(如果你引用的是ui-light.css样式表,输出将会是蓝色的一种更深的阴影):

获取数据

在 Windows Store 应用中,还有其他几种数据访问和存储的方法;数据源可以是本地或远程,你选择的存储方式基本上取决于当前的场景。例如,一个需要保持连接并始终运行的 Windows Store 应用就需要访问来自远程在线源的数据。这些数据可能来源于网页 URL 或 RESTful 服务。理想情况下,使用我们在第三章JavaScript for Windows Apps中介绍的WinJS.xhr函数来消费这些网络服务。

WinJS.xhr函数将向一个 web URL 或服务发起异步请求,并在成功调用后返回响应中的数据。假设我们需要获取一些推文并解析结果;在这个案例中,调用非常直接。为此,提供 Twitter 搜索服务的 URL,该服务将搜索包含windows 8的所有推文,如下面的代码所示:

WinJS.xhr({ 
url: "http://search.twitter.com/search.json?q=windows8"}).then(
function (result) {
});

输出将是一个包含与查询匹配的所有推文的 JSON 字符串,这是许多网站提供的数据格式。Windows 8 JavaScript 对 JSON 有原生支持,因此,我们可以通过调用JSON.parse(jsonString)将 JSON 字符串反序列化为一个对象。让我们将前面的代码添加如下:

WinJS.xhr({
  url: "http://search.twitter.com/search.json?q=windows8"}).then(
  function (result) {
    var jsonData = JSON.parse(result.responseText);
  });

我们还可以使用 Windows 提供的Windows.Storage API 文件从文件中读取数据。如果我们有一个可读文件和一个代表它的storageFile实例,我们可以从文件中读取文本,或者我们可以使用缓冲区读取字节。为了从文件中读取文本,我们可以利用fileIO类提供的readTextAsync(file)函数,如下面的代码所示:

Windows.Storage.FileIO.readTextAsync(sampleFile).then(
function (fileContents) {
  // some code to process the text read from the file
});

当之前的代码成功运行时,这个函数会返回一个通过变量fileContents传递的文本字符串,该字符串包含了文件的内容。

几乎同样的原则适用于从文件中读取字节;然而,我们调用readTextAsync(file)方法,并向其传递文件。在异步过程完成后,我们可以使用then()done()方法捕捉响应中的缓冲区数据,如下面的代码所示:

Windows.Storage.FileIO.readBufferAsync(sampleFile).then(
function (buffer) {
 var bufferData = Windows.Storage.Streams.DataReader.fromBuffer(buffer);
});

在前面的代码中,我们使用了DataReader类从缓冲区读取数据;这个类提供了从内存流读取字符串的功能,并处理缓冲区。

显示数据

我们已经学习了不同数据源的知识,并看到了几个获取数据的示例。现在我们将了解如何格式化和显示这些数据。在前面的示例中,我们看到了如何将数据绑定到任何 HTML 元素,但幸运的是还有更好的方法。更好的方法是使用 Windows 库 for JavaScript,它提供了控件和模板,使格式化和显示数据变得容易。最著名的控件是ListViewFlipView;在绑定和显示数据时,这两种方法应用相同的技巧,但在这个章节中我们将使用ListView。这不仅仅是因为个人偏好,而是利用ListView控件的功能,因为它提供了一种灵活的方式显示数据,并内置了对交叉滑动(触摸)手势的支持;此外,它还进行了性能优化。而且,它提供了一个与 Windows Store 应用一致的外观和行为。绑定和显示数据的步骤如下:

  1. 获取数据。

  2. 创建一个WinJS.Binding.List对象来包装数据。

  3. 创建一个ListView元素。

  4. ListView元素的itemDataSource设置为WinJS.Binding.List对象。

让我们继续使用之前用于通过网络 URL 获取推文的例子;代码返回了一个 JSON 字符串,这里就是我们的数据,所以下一步是创建一个WinJS.Binding.List对象,如下所示:

WinJS.xhr({ 
  url: "http://search.twitter.com/search.json?q=windows8"}).then(
  function (result) {
    var jsonData = JSON.parse(result.responseText);
    //create a binding list object from the json
    var bindingList = new WinJS.Binding.List(json.results);
  });

我们刚刚完成了步骤 1 和 2;第 3 步涉及在 DOM 中创建一个ListView元素,并在 JavaScript 代码中获得它的实例。

在 HTML 中,我们使用如下内容:

<div id="sampleListView" data-win-control="WinJS.UI.ListView" >
</div>

在 JavaScript 中,我们使用以下代码:

//get an instance of the ListView Control
var listView = document.getElementById("sampleListView").winControl;

在第 4 步中,我们将ListView对象的itemDataSource属性设置为bindingList对象的dataSource属性,完整的代码将如下面的代码片段所示:

WinJS.xhr({ 
  url: "http://search.twitter.com/search.json?q=windows8"}).then(
  function (result) {
    var jsonData = JSON.parse(result.responseText);
    //create a binding list object from the json
    var bindingList = new WinJS.Binding.List(jsonData.results);
    //get the list view element from the DOM
    var listView = 
    document.getElementById("sampleListView").winControl;
    //bind the data sources
    listView.itemDataSource = bindingList.dataSource
  });

如果您在default.html页面中添加ListView控件或其他WinJS.UI控件,请记得在函数WinJS.UI.ProcessAll()上的then()done()调用中添加前面的代码,如下面的代码所示:

args.setPromise(WinJS.UI.processAll().then(function () {
  //get the list view element from the DOM
  var listView = 
  document.getElementById("sampleListView").winControl;
  //bind the data sources
  listView.itemDataSource = bindingList.dataSource
}));

添加这段代码的原因是这个函数处理 Windows 库中的 JavaScript 控件并在 DOM 中渲染这些控件。

现在让我们构建并运行项目。输出将是一个包含推文的列表,每个推文都有其属性,如下面的截图所示:

显示数据

尽管ListView控件可以自动绑定数据,但看起来很乱,需要格式化。WinJS控件提供了模板,可以与ListViewFlipView对象结合使用,指定每个项目应如何显示以及它将显示哪些数据。可以通过指定应出现的div元素或使用render方法创建自己的div元素来声明定义模板。让我们亲身体验一下。在 DOM 内部,添加一个div元素,并通过data-win-control属性将其分配给WinJS.Binding.Template,如下所示:

<div id="listTemplate" data-win-control="WinJS.Binding.Template"></div>

然后通过首先添加一个根div元素,然后在该根div内部添加绑定元素来创建模板的内部结构,如下面的代码片段所示:

<div id="listTemplate" data-win-control="WinJS.Binding.Template">
  <div class="templateItem" style ="width:300px; height:100px;">
    <img src="img/#" style="float:left; width: 60px; height: 60px;" 
      data-win-bind="src: profile_img_url" />
    <b>From:</b><span data-win-bind="innerText: from_user_name"></span>
    <br />
    <b>Date:</b><span data-win-bind="innerText: created_at"></span>
    <br />
    <b>Text:</b><span data-win-bind="innerText: text"></span>
  </div>
</div>

您可能在之前的截图中注意到,列出的数据项包含用引号标记的属性,后面跟着一个冒号;例如,"created_at":"from_user":。这些属性代表了从 Twitter 的 web 调用返回的jsonData对象中的数据,并且这些属性作为参数传递给listTemplate元素中的data-win-bind属性,以便在 DOM 中渲染。

接下来,我们应该将这个新创建的模板分配给前面创建的ListView控件,通过在data-win-options属性中指定一个itemTemplate值,如下面的代码所示:

<div id="listViewSample" data-win-control="WinJS.UI.ListView" 
data-win-options="{ itemTemplate: select('#listTemplate') }">
</div>

运行项目后,您将看到与下一张截图类似的界面。由于正在从 Twitter 获取实时数据,值将根据特定查询而变化:

显示数据

排序和过滤数据

我们获取了数据,并使用模板来展示它并将它绑定到WinJS控件上。现在,如果我们需要对数据项进行排序,甚至根据某个特定标准筛选掉不需要的项,该怎么办呢?WinJS库提供的绑定列表 API 无缝地使用内置方法如createSortedcreateFiltered来处理这一点。如果我们回到之前编写的代码,获取推文并创建bindingList变量,这是一个WinJS.Binding.List的实例,并尝试调用createSorted方法,你会注意到自动完成功能列出了为此功能提供的其他两个内置函数,如下面的屏幕截图所示:

Sorting and filtering the data

这两个方法将为它的数据创建一个名为“排序投影”的视图。createSorted方法将返回一个SortedListProjection对象,它代表了一个对其持有的数据进行排序的视图,同样,createFiltered方法将返回一个FilteredListProjection对象,代表了一个对其数据进行筛选的视图。这两个投影的主要优点是它们是完全可观察的,这意味着当列表中的数据发生变化时,其相应的投影将收到通知并更新自己。此外,当投影自身发生变化时,它会通知任何监听的对象其变化。

我们可以通过调用createSorted方法来对这个绑定列表进行排序,该方法接收处理排序逻辑的排序函数参数。让我们按用户名字母顺序排序我们获取的推文。使用以下代码:

//to recall this was the bindinglist variable we had
var bindingList = new WinJS.Binding.List(json.results);
//create a sorted list instance from that bindingList
var sortedList = bindingList.createSorted(function (first, second) {
return (first.from_user_name).toString().localeCompare(second.from_user_name);
});

createSorted函数将在 sorter 函数参数内进行排序逻辑,在这个例子中,比较列表中的from_user_name字段并返回按字母顺序排序的列表。注意比较的字段是列表中数据项的字段。

一旦我们完成了排序,ListView控件的itemDataSource属性现在应该绑定到新创建的sortedList方法,以便看到以下代码:

//pass the sortedList as a datasource
simpleListView.itemDataSource = sortedList.dataSource;

构建并运行项目,你会看到与以下屏幕截图类似的结果:

Sorting and filtering the data

筛选是通过调用createFiltered方法来完成的,该方法创建了一个实时筛选投影,覆盖此列表。筛选投影将反应列表中的变化,并且可能相应地发生变化。此方法接收一个类型为function的参数,这个参数的基本作用是在列表中的每个元素上执行回调方法。例如,我们希望对bindingList应用一个筛选器,该筛选器将检查from_user_name字符串的第二个字符是否为'a',并只返回列表中匹配的项。createFilteredfunction类型的参数将对列表中的每个字符串进行检查;如果条件为真,则将该字符串包含在筛选列表中。要使用筛选器,请参考以下代码片段:

//to recall this was the bindinglist variable we had
var bindingList = new WinJS.Binding.List(json.results);//create a sorted list instance from that bindingList
var filterdList = bindingList.createFiltered(function (filter) {
return filter.from_user_name.toString().charAt(1) == 'a';
});
simpleListView.itemDataSource = filteredList.dataSource; 

运行项目,您将看到列表已根据筛选条件进行了筛选(您可以随意更改筛选条件,以便更好地看到筛选器的效果)。结果将类似于以下屏幕截图:

对数据进行排序和筛选

总结

在本章中,我们已经涵盖了在 JavaScript 应用程序中处理数据的基本知识。我们学习了如何从本地对象获取数据,以及如何通过 Web 服务从 Web 获取数据,并处理返回响应中的数据。

然后我们介绍了如何显示我们从本地对象获取的数据,并将其绑定到ListView控件。最后,我们看到了如何在将数据显示在应用程序之前对其进行排序和筛选。

在下一章中,我们将学习如何使应用程序具有响应性,以便在视图状态发生变化时布局也发生变化,从而使内容始终以良好的格式呈现给用户。

第六章:使应用具有响应性

在本章中,我们将学习应用程序可能存在的不同视图状态以及我们如何使应用程序适应这些视图状态以及各种外形因素和显示尺寸。Windows 8 针对不同的平台,并在具有不同尺寸的各种设备上运行,从大型高清显示器和大笔记本电脑到 10 英寸宽屏平板电脑和 4 英寸宽智能手机。因此,为了遵守 Windows 8 用户体验指南,当用户在这些不同设备上查看应用程序时,他们翻转屏幕以在纵向和横向之间切换,他们放大或缩小,或者应用程序在各种视图状态之间切换,应用程序应该保持相同的视觉感受和功能。应用程序应提供流畅灵活的布局,使其用户界面能够优雅地重新流动并适应这些变化。

在本章中,我们将学习如何使应用程序具有响应性,以便它能够处理屏幕大小和视图状态的变化,并响应放大和缩小。我们首先介绍应用视图状态的概念,然后学习如何使用 CSS 和 JavaScript 处理视图状态的变化。最后,我们将学习有关应用中的语义缩放的概念。

介绍应用视图状态

视图状态代表了用户可以选择以显示应用程序的方式。有四种可能的应用程序视图状态;它们在这里列出,每个的描述如下:

  • 全屏横向视图:使用这种模式,应用会填满整个屏幕,这是所有 Windows 商店应用的默认状态。介绍应用视图状态

  • 全屏纵向视图:使用这种模式,应用会再次填满整个屏幕,但这次是纵向的。介绍应用视图状态

  • 吸附视图:使用这种模式,应用程序填满整个屏幕的狭窄区域(320px),位于屏幕的左侧或右侧;因此,屏幕将同时显示两个应用程序。介绍应用视图状态

  • 填充视图:使用这种模式,应用程序会与一个“吸附”的应用程序并排运行,并填充屏幕上未被该应用程序占据的区域;因此,屏幕将再次同时显示两个应用程序。介绍应用视图状态

如果我们观察前面的图片,将会看到两个应用程序并排运行;一个处于“吸附”视图,另一个处于填充视图。用户通过将另一个应用程序(天气应用)或窗口拖到屏幕上,将一个应用程序(必应新闻)“吸附”到一边。第二个应用程序将成为当前运行的应用程序,并具有填充视图状态,而之前的全屏应用程序将被吸附到一边。现在,用户可以通过按下 Windows 键和句点(.)来切换这些应用程序的视图状态,在“吸附”和“填充”之间切换。

应用程序“吸附”后,其大小会被调整为 320 像素宽,这使得它可以与其他应用程序共享屏幕,从而实现同时显示两个应用程序,使用户能够多任务操作。

注意

只能在水平分辨率大于或等于 1366 相对像素的显示器上拥有吸附和填充视图。这是因为吸附视图将占用屏幕两侧的 320 像素。所以,剩下的 1046 像素将分配给分隔符(22 像素)和填充视图中的应用,填充视图中的应用必须始终具有 1024 相对像素或更大的水平分辨率。因此,1366 x 768 的大小被认为是参考点。

应用总是可以被手动或自动吸附,手动吸附是指用户将其吸附到屏幕的任一侧,自动吸附是指响应另一个应用被拖入全屏模式。因此,你不能阻止应用进入吸附视图。由于用户可以将每个应用吸附起来,如果你没有为应用的吸附视图状态设计,系统将会无论如何调整你的应用大小,可能会裁剪内容,使应用的外观变得混乱。

另一方面,旋转不是强制的,你可以选择让应用支持或不支持。所以,如果你的应用不支持纵向旋转,用户把设备翻转过来,你的应用也不会有任何变化;也就是说,应用不会随着新设备的旋转而旋转。话说回来,当然,为了拥有一个满意的用户,强烈建议支持旋转,毕竟,用户才是应用的目标。

当你点击并打开package_appmanifest文件时,你可以设置应用程序 UI 的选项;这些选项之一是支持的旋转,这是一个可选设置,表示应用的朝向偏好,有四个值:横向纵向横向翻转纵向翻转,如下面的屏幕截图所示:

介绍应用视图状态

处理视图状态

为了适应吸附视图,有两种方法:使用 CSS3 媒体查询或使用 JavaScript 布局变化事件,有时两者都需要。我们用媒体查询来处理可以通过 CSS 样式的元素大小、元素显示(内联、块)和元素可见性来解决的布局变化。通过使用 CSS 媒体查询,可以非常容易地定义不同的样式,这些样式将根据应用的视图状态应用。你可以为每个视图状态使用一个单独的媒体查询,或者通过结合多个媒体查询将相同的样式集应用于多个视图状态。下面的代码展示了匹配不同视图状态的媒体查询的语法;第一个匹配吸附视图状态,第二个匹配视图状态的组合。

@media screen and (-ms-view-state: snapped) {
}
@media screen and (-ms-view-state: fullscreen-landscape), 
  screen and (-ms-view-state: fullscreen-portrait), 
  screen and (-ms-view-state: filled) {
}

所以,如果我们有一组类和其他选择器在 UI 中指定样式,我们可以用每个媒体查询改变这些样式。例如,下面的代码显示了定义为 CSS 网格的两列的页面包装div;一旦进入media查询中的视图状态snapped,它就变成了单列布局:

.appGrid {
display: -ms-grid;
-ms-grid-columns: 120px 1fr; /* 2 columns */
-ms-grid-rows: 120px 1fr;
width: 100vw;
height: 100vh;
margin-left: 120px;
}

@media (-ms-view-state: snapped) {
 /*styles that will be applied when in snapped view state*/
  .appGrid {
    display: -ms-grid;-ms-grid-columns: 1fr; /* 1 column fills the available space */
    -ms-grid-rows: 120px 1fr;
    width: 100%; height: 100%;
    margin-left: 20px; /* margin decreased from 120 to 20 px*/
}
}

前述代码中为宽度值和高度值设置的单位vwvh分别代表视图宽度和视图高度,它们指定了应用占用的完整宽度和高度分辨率。

前面的代码示例展示了 CSS 网格的使用,这是实现流体和适应性 UI 布局的一种非常方便的方法,该布局可以处理视图状态的变化。这是因为网格会自动扩展以分配内容和填充可用空间,并且允许你仅通过 CSS 来指定其内部的元素位置,而与它们在 HTML 标记中的指定顺序无关。这使得指定不同屏幕大小或不同视图状态下的元素不同排列变得容易。

处理窗口大小变化的第二种方法是使用 JavaScript 事件,当需要处理行为和属性的变化时,这是最好的选择,这些变化不能用 CSS 样式来指定,比如WinJS列表视图控制器的滚动方向和控件变化(例如,将水平按钮列表更改为下拉列表控件)。如果我们以列表视图控制器为例,它使用网格模式以填充容器元素和可用空间的方式垂直和水平显示项目,当应用处于横屏、竖屏或填满状态。但是当应用被 snapped 时,列表视图控制器应该重新排列并仅垂直显示项目,以避免使用列表模式进行水平滚动。列表和网格模式不能在 CSS 中指定,因为它们是在data-win-options属性中定义的,如下所示:

data-win-options="{ layout: {type: WinJS.UI.GridLayout} }

这里就是 JavaScript 事件发挥作用的地方,通过注册一个窗口大小变化事件的监听器,我们可以创建特定于视图的布局,该监听器查询由 WinRT 提供的ViewManagement.ApplicationView.value属性,直接查询应用的当前视图状态。下面的示例展示了窗口大小变化事件的监听器的代码:

window.addEventListener("resize", function (e) {
   var viewState = Windows.UI.ViewManagement.ApplicationView.value;
   var snapped = Windows.UI.ViewManagement.ApplicationViewState.snapped;

   if (viewState === snapped) {
        that.listView.layout = new WinJS.UI.ListLayout();    
}
   else if (viewState!== snapped)
    {        
     that.listView.layout = new WinJS.UI.GridLayout(); 
}
});

注意

列表视图(ListView)和网格(Grid)是灵活的控制组件,它们能以最小的开发工作提供对用户界面的最大控制,因为两者都支持内置的灵活布局,并能自动安排和分布其内容。你应尽可能地尝试使用它们。

理解语义缩放

根据 Windows Store 应用的 UX 指南,内容是水平流动的,用户可以通过鼠标或触摸,从左向右或从右向左滚动内容(在某些语言中)。但想象一个场景,你有一个包含大量数据的内容,比如电话簿或者新闻文章列表,在这种情况下,滚动内容以导航变得对用户来说很繁琐。在电话簿应用中,联系人按字母顺序组织,用户必须滚动到最后才能找到一个以字母 z 开头的联系人;也就是说,在列表的末尾,而用户可以缩放到只列出字母的视图级别,并找到那个字母下具体的一个联系人。

同样的,对于一个按类别组织项目/文章的目录应用或新闻应用也适用;不必长时间滚动滚动条以达到所需内容,特别是那些恰巧位于列表末尾的类别,用户可以缩放到类别级别。下面的屏幕快照分别显示了 Windows 8 上的 People 应用和 Bing News 应用的“缩放出”视图:

理解语义缩放

以下是 Bing News 应用在 Windows 8 中的语义缩放视图:

理解语义缩放

注意

语义缩放交互是触摸优化的,因此可以通过捏合和拉伸手势来执行。另外,用户可以通过鼠标滚轮滚动或按住Ctrl键并按加号(+)或减号(-)键使用键盘来进行缩放。

这种技术称为语义缩放,Windows Store 应用使用它来在单个视图中呈现大量相关内容的两个详细级别,并提供更快的导航。这种技术使用同一内容的两个缩放级别来组织数据:一个“缩放进”的详细视图,这是应用显示的默认模式,以及一个“缩放出”视图,它根据某些元数据将项目分组显示。

为了给应用提供语义缩放功能,我们将需要定义这两种语义级别的模式。幸运的是,WinJS.UI为我们提供了使用WinJS.UI.SemanticZoom对象的最佳方式,该对象将渲染一个语义缩放控件,使用户能够缩放同一内容的两个不同的视图。缩放控件使用两个子控件来渲染这两个不同的视图;第一个子控件将提供缩放出视图,另一个将提供缩放进视图或相反。如以下代码所示,声明语义缩放控件在标记或脚本中非常简单:

在 HTML 中:

<div data-win-control="WinJS.UI.SemanticZoom">
  <!-- zoomed-in view -->
  <!-- zoomed-out view -->
</div>

在 JavaScript 中:

var object = new WinJS.UI.SemanticZoom(element, options);

定义了SemanticZoom控件之后,让我们向其中添加两个子控件,以容纳两个视图。

请注意,子控件应通过实现IZoomableView接口来支持语义缩放功能,这样控件就可以作为SemanticZoom控件的放大或缩小视图暴露出来。目前,Windows 库 for JavaScript 提供的唯一支持此功能的控件是 ListView 控件。因此,两个子控件将是两个 ListView 控件的实例,如下面的代码所示:

<!-- zoomed-in view -->
  <div data-win-control="WinJS.UI.SemanticZoom">
    <div id="zoomedInView" data-win-control="WinJS.UI.ListView" >
    </div>

<!-- zoomed-out view -->
    <div id="zoomedOutView" data-win-control="WinJS.UI.ListView">
    </div>
  </div>

现在我们需要一些数据来在这些两个视图中显示。你还记得我们在第四章《使用 JavaScript 开发应用程序》中创建的数据数组吗?当我们开始介绍 ListView 控件时。好吧,让我们再次使用它并添加更多名称。随意添加你喜欢的任何内容;以下是为了参考再次给出的数据:

var dataArray = [
    { name: "John Doe", country: "England", age: "28" },
    { name: "Jane Doe", country: "England", age: "20" },
    { name: "Mark Wallace", country: "USA", age: "34" },
    { name: "Rami Rain", country: "Lebanon", age: "18" },
    { name: "Ryan Air", country: "England", age: "18" },
    { name: "Foster Mane", country: "England", age: "18" },
    { name: "Doe Jane", country: "England", age: "18" },
    { name: "Bow Arrow", country: "England", age: "18" },
    { name: "Amy Sparrow", country: "Italy", age: "18" },
    { name: "Jean Trops", country: "France", age: "56" }

    ];
//create a list object from the array    
var bindingList = new WinJS.Binding.List(dataArray);

现在,我们需要创建一个包含分组信息的此数据源的版本。我们可以使用createGrouped方法来实现,该方法允许我们创建列表的组版本。我们在上一章学习了类似的方法,createdFilteredcreateSortedcreateGrouped方法在列表上创建一个分组投影,并接受以下三个函数参数:

  • getGroupKey:此方法接收列表中的一个项目,并返回该项目所属的分组键。

  • getGroupData:此方法接收列表中的一个项目,并返回代表该项目所属分组的对象的数据。

  • compareGroups:如果第一个组的价值小于第二个组,则返回负值;如果两个组的价值相同,则返回零;如果第一个组的价值大于第二个组,则返回正值。

以下代码将创建一个包含我们bindingList对象的组版本,该对象使用每个项目名称的第一个字母来定义元数据:

// Sort the group
function compareGroups(leftKey, rightKey) {
return leftKey.charCodeAt(0) - rightKey.charCodeAt(0);   
}

// Get the group key that an item belongs to.
function getGroupKey(dataItem) {
return dataItem.name.toUpperCase().charAt(0);   
}

// Get a title for a group
function getGroupData(dataItem) {
return {
    title: dataItem.name.toUpperCase().charAt(0);
}; 
}
// Create the groups for the ListView from the item data and the grouping functions
    var groupedItemsList = bindingList.createGrouped(getGroupKey, getGroupData, compareGroups);

为了将分组数据绑定到放大视图的ListView控件上,我们将它的itemDataSource属性设置为groupedItemsList.groups.dataSource,它包含分组信息,并将放大视图的ListView控件的itemDataSource属性设置为groupedItemsList.dataSource,它包含要显示的项目,如下所示:

var zoomedInView = document.getElementById("zoomedOutView").winControl;
var zoomedOutView = document.getElementById("zoomedOutView").winControl;

zoomedInView.itemDataSource = groupedItemsList.dataSource;

zoomedOutView.itemDataSource = groupedItemsList.groups.dataSource;

有了这些知识,你可以按照我们在第四章《使用 JavaScript 开发应用程序》中学到的内容,为视图创建模板,以便更好地展示数据。

总结

在本章中,我们介绍了用户可以选择显示应用程序的不同视图状态。然后,我们学习了如何通过 CSS 和媒体查询或使用检测窗口大小的 JavaScript 事件处理程序来适应这些视图状态的变化。

最后,我们学习了语义缩放以及如何轻松地将此功能集成到应用程序中。

在下一章节中,我们将学习关于动态磁贴的知识,如何向应用图标添加磁贴和徽章,以及如何使磁贴具有动态效果,并从应用向用户发送通知。

第七章: 用磁贴和通知让应用上线

Windows 8 的开始屏幕上闪烁着磁贴,这些磁贴不仅仅是与特定应用相关的大图标。在本章中,我们将学习应用磁贴的概念、磁贴类型以及每个磁贴的用途。此外,我们还将了解如何为应用定义这些磁贴。然后,我们将介绍通知以及不同的通知方法,并编写代码创建并实现应用的简单通知。

介绍磁贴、徽章和通知

Windows 8 应用的独特特性之一就是磁贴的概念。而且,正是这些磁贴使得 Windows 8 应用与众不同。应用用色彩的盛宴、标志和信息装饰开始屏幕。磁贴是应用在开始屏幕上的图形表示。另外,应用磁贴是应用的启动点;点击磁贴将启动应用程序,这与我们桌面上的 Windows 应用快捷方式类似。

以下是一张来自全新安装后的开始屏幕的截图,显示了几块应用磁贴:

介绍磁贴、徽章和通知

每个已安装的应用都有一个默认磁贴,在安装后立即添加到开始屏幕上。这个默认磁贴有一个默认的标志图像,代表应用标志或任何其他品牌来识别应用。默认情况下,磁贴上显示静态内容,包含指定应用名称的文本和代表标志的图像。之前的截图展示了 Windows 8开始屏幕上基本应用磁贴的例子。你可以在之前的截图中注意到磁贴有两种尺寸:正方形(150x150)px 和矩形(310x150)px。按照 Windows 8 的命名约定,这两种尺寸分别是正方形和宽磁贴。正如你所看到的,这两种尺寸都显示文本和图像以及一个通知徽章来显示某种状态;我们稍后会看到徽章是什么。所有应用都默认支持正方形磁贴;支持宽磁贴是可选的。如果一个应用没有为默认磁贴提供宽标志图像,用户将无法从开始屏幕菜单中把应用磁贴放大。另外,如果应用包括了宽标志图像,Windows 8 会默认以宽格式显示磁贴。

用户可以通过切换宽磁贴和正方形磁贴来个性化他们的开始屏幕,只要应用磁贴包含两个版本。如果一个应用没有包含宽标志,用户将无法把磁贴放大。用户可以右键点击应用,开始屏幕应用栏将出现。从那里,用户可以点击放大选项来更改磁贴的大小。下面的截图展示了用户如何将商店应用的磁贴从正方形更改为宽磁贴。

介绍磁贴、徽章和通知

Windows 8 只要没有通知要显示,就会显示默认磁贴图像,当通知到期时,或者当用户关闭实时通知时,它会恢复到默认图像。磁贴的大小和其他图像(如小标志,显示在搜索结果旁边应用名称旁边,和商店标志,显示在 Windows 商店上)都包含在应用包中,并在应用清单中的应用 UI面板的磁贴图像和标志设置下指定。在清单编辑器中,我们可以为磁贴指定背景颜色,显示在磁贴上的文本颜色,以及应用的简称;更重要的是,我们可以浏览(并选择)不同磁贴大小的图片,如下面的屏幕截图所示:

介绍磁贴、徽章和通知

如果你检查你在前几章中创建的开始屏幕上的test应用,你会看到应用磁贴显示 150x150 像素默认标志的图片;它填满了方形磁贴,无法放大。尝试选择一个宽标志来运行应用,然后将应用磁贴放大以查看更改。磁贴的内容是基于 Windows 提供的一套模板在 XML 中定义的,以保持 Windows 8 的外观和感觉。磁贴的内容可以在这些模板中定义,通过提供相应的文本或图片,或者两者都有。磁贴还显示徽标或简称。

除了默认磁贴外,还有辅助磁贴,它允许用户在开始屏幕上显示特定应用的内容。辅助磁贴是通过应用栏中的固定到开始选项创建的,用户可以选择将应用的特定位置或内容固定到开始屏幕上。当从辅助磁贴启动应用时,用户会被引导到应用中的特定位置。例如,我们可以将应用中的一个联系人固定下来,辅助磁贴会个性化开始屏幕,显示该联系人的更新信息;或者,也许我们可以固定一个城市的天气。辅助磁贴允许用户个性化对他们重要的开始屏幕信息。下面的屏幕截图显示了天气应用的两个磁贴;左边是显示当前位置天气的默认磁贴,右边是显示伦敦市天气的固定内容的辅助磁贴:

介绍磁贴、徽章和通知

应用图块可以在应用未运行时传达与应用相关的状态信息,使用一个通知徽章来表达总结或状态信息,数值在 1 到 99 之间(数值大于 99 将显示为 99+)或者它可以是一组 Windows 提供的图像符号,称为图标。徽章出现在图块的右下角,并且可以同时在正方形和宽图块上展示。

应用的另一个与 UI 相关的概念是提示通知;这是一个出现在屏幕右上角的弹出通知。提示通知允许当应用不在屏幕上运行时,即使用户正在使用另一个应用,或者当在桌面而不是 Windows 8 的开始屏幕上时,应用向用户发送信息。

提示

需要注意的是,应用图块不应作为广告表面使用。根据 Windows 商店应用的条款,在大多数情况下,使用图块来展示广告是不允许的。

使用动态图块

应用图块是您应用的核心部分;很可能是它是最常被看到的部分。这就是为什么您应该利用这个图块来吸引用户注意力,并通过实现一个动态图块让他们回到应用中。动态图块是吸引用户到您应用的理想方式之一,通过展示显示应用内部最佳情况的的重要信息。例如,Windows 8 中的应用有一个动态图块,它会定期间隔更改联系人的图片。

与静态图块显示不同,默认内容通常是一个完整的图块标志图像和指示应用名称的文本,动态图块可以更新默认图块以显示新内容。动态图块可以用来让用户了解他们的联系人,显示事件信息,或显示最新消息。此外,动态图块可以显示应用更新的摘要,例如未读邮件的数量,从而给用户一个启动应用的理由。

发送通知

图块、次要图块、锁屏图块和提示可以通过多种类型的通知进行更新。这些通知可以通过本地 API 调用或从运行在云上的某些服务调用生成。此外,有四种不同的通知传递方法可以发送图块和徽章更新以及提示通知。这些方法包括以下内容:

  • 本地:当应用在屏幕上或后台运行时发送通知,以更新应用图块或徽章,或者弹出一个提示通知。

  • 定时发送:在已知的时间发送通知,例如,即将到来的约会的提醒。

  • 周期性:通过定期轮询固定时间间隔从云服务器获取新内容的方式发送通知;例如,每 12 小时更新一次天气。周期性通知与图块和徽章一起工作,但不适用于提示。

  • 推送通知:它即使应用程序没有运行,也能直接从云服务器向屏幕发送通知。推送通知非常适合于包括实时数据的情况,比如社交网络更新或时间敏感信息,如即时消息或突发新闻。此通知方法可用于磁贴、徽章和弹出式通知。

默认情况下,本地磁贴通知不会过期,但可以给予并且理想情况下应该给予一个过期时间;然而,推送、周期性和计划性通知在提供后三天过期。通过指定一个过期时间,应用程序可以在磁贴在达到过期时间时仍然显示时,从磁贴中删除通知内容。

选择通知方法主要取决于您想要传递的信息以及应用程序的性质和内容。

小贴士

请记住,用户可以随时关闭或打开磁贴通知,因此要小心不要因不必要的弹出式通知而让用户感到困扰。

为了实现通知功能并允许应用程序传输弹出式通知,我们必须在清单文件中将应用程序声明为支持弹出式通知。一旦应用程序被声明为支持弹出式通知,它将被添加到PC设置中通知部分的 app 列表中。下面的屏幕截图显示了如何更改支持弹出式通知设置:

发送通知

现在让我们编写一些代码来创建一个简单的本地弹出式通知。我们将需要非常频繁地使用Windows.UI.Notifications命名空间;因此,为了简化,让我们声明一个命名空间变量,如下所示:

var notifications = Windows.UI.Notifications;

接下来,我们需要通过从 Windows 提供的模板中选择一个来提供ToastTemplateType;这些模板确保应用程序在弹出式通知中保持预期的 Windows 8 外观和感觉。有文本模板,如:toastText01toastText02toastText03toastText04。图像和文本模板有:toastImageAndText01toastImageAndText02toastImageAndText03toastImageAndText04

WinJS为这些模板提供 IntelliSense,当我们对通知变量调用ToastTemplateType枚举时,这些模板将被列出,如下面的屏幕截图所示:

发送通知

在这个例子中,我们将选择toastText01,它只包含一个文本字符串,最多跨越三行。如果文本超过三行,它将被截断。然后我们将获取一个 XML 文档的模板内容,如下面的代码所示:

var template = notifications.ToastTemplateType.toastText01;
var templateXML = notifications.ToastNotificationManager.getTemplateContent(template);

templateContent变量将包含以下 XML 骨架:

<toast>
  <visual>
    <binding template="toastText01">
      <text id="1"> </text>
    </binding>
  </visual>
</toast>

接下来我们需要做的是填充这个 XML 模板的内容,因此我们需要检索具有标签名text的元素,如下面的代码所示:

var toastTextElements = templateContent.getElementsByTagName("text");
toastTextElements[0].appendChild(templateXML.createTextNode("This is a new toast notification"));

然后我们根据刚刚指定的 XML 内容创建弹出式通知,如下所示:

var newToast = new notifications.ToastNotification(templateXML);

最后,我们将创建一个toastNotifier变量,它将把我们在以下代码中定义的newToast通知发送到屏幕:

var toastNotifier = notifications.ToastNotificationManager.createToastNotifier();
toastNotifier.show(newToast);

WinJS.UI.processAll()方法上调用then()函数时编写要执行的代码;因此,当应用程序启动时,就会出现弹出通知。如果我们现在运行应用程序,屏幕右上角将弹出以下通知:

发送通知

提示

请注意,应用于通知的背景颜色是应用程序清单中为应用程序磁贴声明的颜色。

之前的代码允许我们实现一个最小的通知;您可以尝试使用其他的通知模板并比较结果。

总结

在本章中,我们介绍了磁贴、徽章和通知的概念,并学习了它们之间的区别以及我们可以使用它们的地方。

我们还学习了如何发送通知,并编写了一个示例代码,实现了向屏幕发送一个非常简单的通知。

在下一章中,我们将学习如何使用 Windows Live 服务来实现用户认证,并允许用户使用他们的电子邮件 ID 登录。

第八章.用户登录

一个 Windows 商店应用可以针对登录应用的个人用户进行个性化设置;因此,使得认证过程非常简单是非常重要的。Windows 8 允许用户使用 Microsoft 账户登录他们的设备,从而使开发者更容易为应用用户提供单点登录体验。此外,Windows 8 提供了一个软件开发工具包SDK)和一组 API,以便 Windows 商店应用能够使用 Microsoft 账户实现单点登录,并与 Microsoft SkyDrive、Outlook.com 和 Windows Live Messenger 中的信息集成。在本章中,我们将学习关于 Live Connect API 以及如何使用此 API 登录用户并获取用户资料信息。我们将学习如何开始使用 Live Connect 集成应用,并展示一些代码,介绍 Live Connect API 可以执行的一些基本功能。

介绍 Live Connect

有很多场景,应用需要认证用户并访问他们的资料信息,从简单地显示带有用户姓名的欢迎信息,到访问他们的资料信息,并为用户提供个性化体验。此外,你可以通过与允许与文档和媒体协作并访问云上文件或与 Outlook 协作处理联系人和日历的产品和服务集成,构建提供强大功能的应用。你的应用需要与 Microsoft 账户集成认证的场景可以总结如下:

  • 应用需要用户登录才能运行,例如,一个联系人应用

  • 应用可以在用户不登录的情况下运行,但对于登录的用户,它能提供更加个性化的体验;例如,一个天气或新闻应用

  • 应用包含一些与 SkyDrive 或 Hotmail 集成的功能,因此需要 Microsoft 账户登录

认证过程以及与 Microsoft 云服务(如 Microsoft SkyDrive 和 Outlook)的集成使用 Live Connect 实现。Live Connect 是一组 API,允许将应用与这些兼容服务集成。这些 API 由 Live SDK 提供,它是开发应用的 Microsoft 软件开发工具包之一。Live Connect API 利用一个开放标准,使你能够专注于实现功能,而不是在学习新概念上花费时间,而你想要做的只是实现由这个新概念引入的功能。例如,你可以使用开放认证OAuth)标准与 Facebook 和其他社交网络 API 的认证服务集成,而无需了解这些社交网络 API 内部认证过程的工作原理;更重要的是,你可以使用你熟悉的编程语言进行调用。Live Connect 使用的开放标准包括以下内容:

  • OAuth 2.0:这是 OAuth 协议的最新版本,是一个开放标准,用于验证用户的凭据。包括 Live Connect 在内的社交网络 API 已采用 OAuth 作为其认证标准。OAuth 基本上允许用户使用 Live Connect 授权 Web 服务进行认证,而无需将他们的机密登录凭据与应用程序共享。

  • 代表性状态转换(REST):这是一种在实现网络服务时流行的架构风格。在 Windows 商店开发中,REST 允许我们通过 Live Connect API 轻松请求用户信息。这个 REST 实现支持标准的 HTTP 方法,如 GET、PUT、POST 和 DELETE。

  • JSON:这是JavaScript 对象表示法的缩写,是一种用于表示网络服务中信息的轻量级数据交换格式。Live Connect 以 JSON 格式交换用户信息。例如,当函数请求用户个人资料信息时,该信息将以包含first_namelast_name等字段的响应对象的形式返回。

在 Windows 8 中,用户可以通过使用他们的微软账户(Hotmail、Live 和 Outlook)登录设备,因此,应用程序可以利用这一功能提供单点登录体验。例如,Windows 8 的主要应用程序,如人脉、邮件和信息,以及微软网站,如 Outlook 和 Bing,都可以利用单点登录,所以用户在登录到电脑后不需要再登录这些应用程序和网站;这些过程将由系统代为完成。我们开发的应用程序可以通过实现 Live Connect API 的功能来实现相同的效果,这样如果用户已经登录到设备,他们就可以直接在我们的应用程序中进行认证。

在我们开始使用 Live Connect 功能之前,有两个先决条件:

  • 在 Windows 商店注册应用程序

  • 在 Windows 商店仪表板中为 Windows 商店应用程序配置 Live Connect 设置

首先,我们需要在 Windows 商店仪表板中注册应用程序,该仪表板可以通过以下链接访问:

appdev.microsoft.com/StorePortals/en-us/Home/Index

登录到商店仪表板;为此你需要微软账户的凭据,然后你会看到以下屏幕:

介绍 Live Connect

这是您的整个应用列表的主页。同时也是新用户首次看到的屏幕。为了让应用开始使用 Live Connect API,必须对其进行注册并相应地配置其设置。此外,对于要使用 Live Connect 的 Windows Store 应用,它需要有一个包含包名和发布者的包身份,这将唯一标识该应用。要获取包身份,我们需要提交应用;这基本上是为您的应用预留一个名称,添加其描述,并提交认证。在这个阶段,我们不需要将应用提交到 Windows Store 进行认证;我们只需要在 Windows Store 开发者账户中为其输入一个名称。为此,我们将首先点击提交应用链接,这是您在上一个屏幕快照中注意到的左侧菜单下仪表盘下的第一个链接。您将被引导到提交应用页面,如下面的屏幕快照所示:

Introducing Live Connect

点击应用名称为应用提供一个唯一的名称,仅为此应用保留;其他应用不能使用它。如果应用没有完全提交到商店,预留将持续一年。请确保您有权使用该名称,因为应用将在 Windows Store 中以该名称列出。请注意,应用名称应与在应用清单文件中的DisplayName字段中输入的名称相同。要继续,请在提供的文本框中输入一个值,然后点击预留应用名称;现在名称已被预留;点击保存返回应用摘要页面。现在,应用将在仪表板上以包含删除编辑链接的磁贴状框中列出。下面的屏幕快照显示了一个用于示例的测试应用:

Introducing Live Connect

接下来我们需要为应用配置 Live 服务。为此,请按照以下步骤操作:

  1. 如果您在仪表板页面,找到您的应用并点击编辑。您将被引导到应用摘要页面。

  2. 点击高级功能

  3. 点击推送通知和 Live Connect 服务信息

  4. 您将被引导到推送通知和 Live Connect 服务信息页面,并需要遵循标题下如果您的应用使用 Live Connect 服务,请审查的步骤。包括以下步骤:

    • 识别您的应用

    这包括在应用的清单中定义正确的身份值。这些值在我们预留应用名称时创建。我们可以用两种方式设置这些值:

    1. 我们可以通过使用 Visual Studio 2012 中的商店菜单为 Windows 8 应用设置应用的身份值。在一个打开的项目中,在顶部菜单中点击项目;然后从出现的菜单中选择商店,导航到子菜单,并点击将应用与商店关联。跟随并完成向导,该过程在下方的屏幕截图中说明:介绍 Live Connect

      在向导的第一个步骤中,如前屏幕截图中数字 2 所标记的,你将会被提示使用你的 Microsoft 账号进行登录。

    2. 另外,我们也可以在应用清单文件中手动设置应用的包身份。用文本编辑器打开你的应用的 AppManifest.xml 文件,并使用 NamePublisher 值设置 <identity> 元素的这些属性。当你在 Windows Store 上预留你的应用名称时,Windows Store 创建了这些值,你可以从 Windows Store 仪表板中获取。下面的代码显示了包含这些值的 XML 设置节的语法:

      <Identity Name="19474XXX.BookTestApp" Publisher="CN=F0476225-496D-4EDF-946E-46F6247D5B9A"" />
      
      • 认证你的服务

    这一步骤包括获取客户端密钥值。Live Connect 服务使用客户端密钥来认证从你的服务器发出的通信,以保护你的应用的安全。下面将显示以下客户端密钥:

    zqMKo4G0t3ICZe1h06ofrKYZ1/hVuZXn

    请注意,你总是可以回到该页面并创建一个新的客户端密钥,如果有需要的话。

    • 向 Live Connect 用户代表你的应用

      这是配置 Live Connect 服务信息的最后一步,涉及指定 Live Connect 服务用来提示用户授权访问和交互他们数据的意图对话框的设置。在这一步中,你可以提供他们到你自己的服务条款和隐私政策的链接,并上传你的应用标志在授权对话框中显示。

这就完成了在 Windows Store 上应用的注册和配置过程。现在进入编码部分;我们将看看如何实现基本的登录和认证功能。

将用户登录到应用

为了开始编码登录功能,我们需要在我们的应用解决方案中引用 Live Connect API;为此,我们首先应该下载并安装 Live SDK for Windows,如果你还没有安装的话。它可以通过以下链接从 Live Connect 开发者中心 找到并下载:

msdn.microsoft.com/en-us/live/ff621310.aspx

在那页面上,你也可以找到支持 Android 和 iOS 的 Live SDK 版本的下载链接。或者,你可以在 Visual Studio 中直接使用 NuGet 包管理器找到并安装 Live SDK 到你打开的解决方案中。

为此,打开在 Visual Studio 中的应用解决方案,从解决方案资源管理器中右键点击解决方案,然后点击管理 NuGet 包…

将出现一个对话框,在对话框顶部右上角提供的搜索文本框中输入livesdk;包管理器将在线搜索所有包含livesdk的相关匹配项。从搜索结果中找到Live SDK并单击安装。这将安装 Live SDK 包并将其包括在引用中。

下面的屏幕快照显示了屏幕上的管理 NuGet 包对话框:

将用户登录到应用

接下来,我们在项目中添加对 Live Connect APIs 的引用。为此,请按照以下步骤操作:

  1. 解决方案资源管理器中,右键单击References,然后单击添加引用

  2. 点击Windows | Extension SDKs | Live SDK

  3. 点击添加,然后点击关闭

一旦我们添加了对 Live SDK 的引用,解决方案中就会添加 JavaScript 文件wl.js。为了方便,我建议您将此文件复制并粘贴到您的js文件夹中。然后我们添加一个指向新添加的wl.js<script>元素,这样我们就可以在default.html页面中使用 Microsoft IntelliSense for this API,如下面的代码所示:

<script src="img/wl.js"></script>

请注意,为src属性设置的文件路径包含///;我们使用三个反斜杠(\)的原因是因为需要通过三个目录层次结构来到达位于References下的LiveSDKHTML下的js目录中的wl.js文件。

添加对此脚本文件的引用将在引用的 HTML 文件中启用 Microsoft IntelliSense。

此外,如果您想要在 JavaScript 层面启用 intelliSense,请在调用此 API 方法的头部的 JavaScript 文件中添加引用,如下面的代码所示:

/// <reference path="///LiveSDKHTML/js/wl.js" />

提示

建议您将使用wl.js的代码写在单独的 JavaScript 文件中。这将使修改和调试应用程序更加容易。

让我们添加一个按钮,当点击时,将提示用户登录并响应同意对话框。

以下标记将添加一个具有 IDsignInbutton和一个具有 IDlogdiv。这个div将用于在屏幕上显示点击登录按钮时发生的内容:

<div id="liveSDK">
  <h1>Windows Live Connect</h1>
<div>
<div>
  The authentication in this section uses the Windows Live connect.
  <br />
  Sign in to your Microsoft account by clicking on the below button:
</div>
<button id="signIn">Sign in</button><br /><br />
<div id="log"><br /></div>
</div> 
</div>

首先,通过调用WL.init方法初始化 Live Connect APIs(应用程序必须在每页上都调用此函数,然后再调用库中的其他函数),然后在页面加载时订阅auth.login事件,如下面的代码所示:

WL.init();
WL.Event.subscribe("auth.login", function () {
  if (WL.getSession()){
    log("You are now signed in!");
  }
});

auth.login事件的回调函数中,我们使用WL.getSession()方法检查当前会话对象的状态;如果存在,则用户已登录。

接下来,我们将为按钮的点击和日志功能添加登录功能:

document.querySelector("#signIn").onclick = function (e) {
  if (WL.getSession()){ 
    log("You are already signed in!");
}
  else {
    WL.login({ scope: "wl.signin" });
  }
};
//log what is happening
function log(info) {
  var message = document.createTextNode(info);
  var logDiv = document.querySelector("#log");
  logDiv.appendChild(message);
  logDiv.appendChild(document.createElement("br"));
}

在用户点击登录按钮时,我们首先检查是否有会话,以及用户是否已经登录。如果没有会话,我们尝试通过调用WL.login方法登录用户;这个方法需要一个参数scope: "wl.signin"。像"wl.signin""wl.skydrive"这样的作用域值用来表示如果用户同意,应用将能够访问用户数据的哪些部分。

在前面的代码行中,我们使用此格式定义了一个作用域:scope: "wl.signin",这是一个字符串参数。我们也可以定义多个作用域,但格式略有不同,使用字符串值的数组,如下面的代码行所示:

scope: ["wl.signin", "wl.skydrive", "wl.basics"]

作用域也可以在初始化库时设置,通过将其作为可选参数传递给WL.init方法。此外,login方法中输入的作用域值将覆盖并扩展在init方法中定义的作用域列表。而且,WL.init的作用域值在没有由login方法提供的作用域时使用。

WL.login函数只能在用户动作响应时调用,比如我们例子中的点击按钮,因为该函数可能导致启动同意页面提示。

log函数只接受文本,简单地将它追加到 ID 为logdiv内容中,这样我们就可以获取发生了什么的状态信息。

现在运行应用。您将看到以下截图,提示您登录;随后会出现同意对话框:

将用户登录到应用

按照前一个截图出现的步骤操作。最后,应用将显示消息:您已登录!

获取用户信息

login函数返回一个承诺对象,使我们能够在成功的情况下适当反应,即用户成功登录。我们的目标是获取用户的个人资料信息。因此,我们需要修改之前展示的WL.login调用,并请求额外的作用域,如wl.basicwl.birthdaywl.emails,这将允许我们检索基本个人资料信息,如名字和姓氏,同时也获取用户的生日和电子邮件。在登录方法的成功的回调中,我们然后执行对WL.api函数的调用,它返回我们所需的用户个人资料信息。从技术上讲,WL.api函数对 Live Connect Representational State Transfer (REST) API 进行调用。WL.api调用的语法如下面的代码所示:

WL.api({
    path: "me" ,
    method: "GET"
});

在前面的代码示例中,我们传递了me快捷方式以请求有关已登录用户的信息。路径参数指定了到 REST API 对象的路径,在本例中为对象me,它包含诸如first_namelast_name的属性;WL.api返回一个承诺对象,因此我们可以对其调用then(),并在成功回调中请求用户的名字和姓氏,这些信息由作用域"wl.basic"提供。代码如下所示:

WL.api({
  path: "me" , method: "GET"
  }).then(
  function (response) {
    log("First Name: " + response.first_name);
    log("Last Name: " + response.last_name);
    log("Email: " + response.emails.preferred);
    log("Birthday: " + response.birth_day + "/" + response.birth_month);
}

将之前的代码添加到登录按钮点击处理程序中调用的 WL.loginthen 方法中,完整的代码如下:

document.querySelector("#signIn").onclick = function (e) {
  WL.login({
    scope: ["wl.signin", "wl.basic", "wl.birthday", "wl.emails"]
    }).then(
    function (response) {
      WL.api({
         path: "me", method: "GET"
         }).then(
         function (response) {
           log("First Name: " + response.first_name);
           log("Last Name: " + response.last_name);
           log("Emails: " + response.emails.preferred);
           log("Birthday: " + response.birth_day + "/" + response.birth_month);
           }
         );
     }
  );
};

现在运行应用,你会注意到同意对话将更改,请求访问有关你的出生日期和电子邮件地址的信息,如下面的屏幕截图所示:

获取用户信息

当你批准同意提示后,点击登录按钮,应用将显示所请求的信息,如下面的屏幕截图所示:

获取用户信息

提示

为了遵守微软为 Windows 商店应用设置的指南,你不应该在应用中的任何地方显示 Microsoft 账户登录或登出选项,除了设置弹出控件或任务的一部分。用户期望账户管理选项在设置磁贴中,改变其位置会导致用户体验不一致和意外。

摘要

在本章中,我们介绍了 Live Connect,并学习了其核心概念,还看到了我们可以使用这些 API 做些什么,应用启动调用 API 所需的设置,以及如何编写基本的代码来调用 API。

我们还涵盖了如何在商店中注册应用,以及如何在 Visual Studio 中与商店通信。

然后我们利用 Live Connect API 登录用户到应用。此外,我们还学会了在用户同意后如何获取会话信息。

在下一章中,我们将学习关于应用栏的知识,如何为应用创建一个应用栏,以及如何向其中添加菜单按钮。

第九章:添加菜单和命令

在本章中,我们将学习关于应用栏的知识,并了解它是如何工作的,以及在哪里可以找到应用栏。此外,我们还将介绍如何声明应用栏以及向其添加控件。

了解应用栏

当你运行一个 Windows 商店应用时,你所看到的就是一个全屏应用,它让你能够沉浸在应用的内容中;然而,这时你可能自己会想所有的按钮和控件都去哪了。它们都包含并隐藏在应用栏中——当然,直到你需要它们为止——以避免分散注意力,并让屏幕上的每个像素都用于应用的内容。

应用栏位于屏幕底部,当用户触发时会出现。这可以通过触摸手势(通过从底部边缘向上轻触或滑动,或从顶部边缘向下轻触),使用鼠标(通过右键点击),或使用键盘(通过 Windows + Z快捷键)来完成。应用栏通常包含与当前屏幕相关的控件。默认情况下,控件在屏幕的左右两侧平均分配。左侧包含当前在应用中显示内容的特定命令,而右侧包含适用于应用所有页面的全局命令。应用栏也可以包含特定于应用中单个元素的命令。

让我们来看一个应用栏的示例。下面的屏幕截图显示了 Microsoft Bing 应用的应用栏,其中包含四个命令,分别是复制链接复制另存为设为锁屏背景

了解应用栏

应用栏的隐藏机制使用户能够集中精力并沉浸在内容中,同时将干扰降到最低。它在用户需要时提供一致且易于访问的命令,并且他们可以轻松地显示或隐藏应用栏。

当我们尝试使用鼠标、触摸或键盘显示应用栏时,另一个栏会同时出现在屏幕顶部。这是导航栏,虽然它可能看起来很相似,但它并不是应用栏。导航栏用于显示帮助我们导航应用程序不同部分的控制器。

如果存在应用栏,它应该始终对用户可用,并因此适应用户界面在 snapped 和 portrait 视图之间的变化。例如,如果你在 snapped 视图上看不到所有的命令,你可以尝试将它们组合成菜单并提供命令的提示,尽管 Windows 会自动隐藏标签并相应地调整内边距。

提示

强烈建议你不要更改由WinJS提供的默认布局应用的按钮的大小或内边距,因为它是为了在所有支持屏幕大小上适配 10 个命令而设计的;更重要的是,它还支持触摸手势。因此,更改布局可能会打乱这种行为。

应用栏是由WinJS库使用WinJS.UI.AppBar对象提供的。

在标记中声明应用栏非常简单。我们从通过指定data-win-control属性中的WinJS.UI.AppBar控制来从一个简单的div元素创建一个应用栏开始。语法如下:

<div id="testAppBar" data-win-control="WinJS.UI.AppBar"> </div>

前面的语法将创建一个空的应用于当通过鼠标或向上滑动触发时显示的应用栏。

应用栏是用来包含命令按钮的,所以让我们在应用栏中添加一个命令按钮。为了创建一个应用栏命令按钮,我们将使用一个button元素,并指定其data-win-control属性为AppBarCommand,如下面的代码所示:

<div id="testAppBar" data-win-control="WinJS.UI.AppBar">
  <button data-win-control="WinJS.UI.AppBarCommand"></button>
</div>

前面的语法将在应用中显示一个空的命令按钮。我们可以通过在data-win-options属性中指定一些选项来给这个命令按钮添加功能。这些选项如下:

  • type:此选项用于从以下值指示命令的类型 - buttontoggleseparatorflyout

  • Id:此选项用于指定命令的 ID。

  • label:此选项用于指定应用栏上显示的文本。

  • Icon:此选项用于指定用于显示命令的图标,可以通过从 Windows 提供的AppBarIcon列表中选择一个值,例如pinunpinacceptcanceldelete,或者通过指定自定义 PNG 图像文件的路径来指定。

  • section:此选项用于指示命令所属的部分,可以是selectionglobalselection部分会将命令放在应用栏的左侧,这是为上下文命令或页面特定命令保留的位置,而global部分会将命令放在应用栏的右侧,这是为全局命令或应用级别命令保留的位置。

  • tooltip:此选项用于指定当用户将鼠标悬停在命令上时显示的信息工具提示(提示)。

以下代码显示了在添加这些选项后,我们声明的前一个示例中的命令按钮的语法将如何:

<button data-win-control="WinJS.UI.AppBarCommand" 
data-win-options="{type:'button', id:'testCmd', label:'Test Command', icon:'placeholder', section:'global', tooltip: 'Command Tooltip' }">
</button>

运行应用,您将看到一个应用栏,如图所示:

了解应用栏

如您在前面的屏幕截图中所见,应用栏包含一个带有占位符图标的按钮,标记为Test Command;当鼠标悬停在上面时,将显示工具提示Command Tooltip

为命令添加功能

我们刚刚创建的应用栏目前还不能做什么,所以让我们添加另一个命令并检查其他类型。但在那之前,我们需要在两个命令之间添加一个分隔符;可以通过应用栏默认包含的hr元素来创建它,除了命令按钮之外。

hr元素还需要设置data-win-control="WinJS.UI.AppBarCommand"属性。创建分隔符的语法如下所示:

<hr data-win-control="WinJS.UI.AppBarCommand"data-win-options="{type:'separator', section:'global'}" />

在分隔符之后,我们将添加一个新的按钮命令,这次我们选择固定图标;语法将如下所示:

<div id="testAppBar" data-win-control="WinJS.UI.AppBar">
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{ type:'button', id:'pinCmd', label:'Pin to start', icon:'pin', section:'global', tooltip: 'Pin the app'}">
</button>
<hr data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'separator', section:'global'}" />
<button data-win-control="WinJS.UI.AppBarCommand" data-win-options="{type:'button', id:'testCmd', label:'Test Command', icon:'placeholder', section:'global', tooltip: 'Command Tooltip' }">
</button>
</div>

现在运行应用,你应该会看到两个命令按钮,一个带有固定图标,另一个带有占位符图标,以及这两个之间的分隔符,看起来像一个hr元素。以下是当用户悬停在标有固定到启动的命令上时应用栏的结果屏幕快照:

为命令添加功能

这些命令在应用栏上看起来很不错,但点击后仍然什么也不做,所以让我们给固定到启动命令按钮添加一些功能并开始应用固定。

为了给命令按钮添加一些功能,我们需要从应用栏中获取它们,并为它们添加一个click事件处理程序。以下代码获取应用栏并将其设置为变量。然后,它使用应用栏的Id属性获取该应用栏中的特定命令,并将其点击事件附加到函数上:

//get the appbar control
var appbar = document.getElementById("testAppBar").winControl;
//get the command and add an event handler to it
appbar.getCommandById("pinCmd").addEventListener("click", clickPin, false);
//function to be called when the command is clicked
function clickPin() {
var dialog = new Windows.UI.Popups.MessageDialog("The pin command in the bar has been clicked.");
dialog.showAsync();
}

现在运行应用,并点击固定到启动命令按钮;屏幕上将出现一个弹出消息对话框。

应用栏默认位于应用的底部,可以改为位于屏幕顶部;然而,它应该包含导航元素,以将用户移至不同的页面。根据 Windows 8 的 UX 指南,顶部的应用栏是一个导航栏。回到代码,我们可以通过简单地设置应用栏控件的data-win-options属性的placement属性的值,将应用栏的位置从底部更改为顶部,如下面的代码所示:

<div id="testAppBar" data-win-control="WinJS.UI.AppBar" data-win-options="{placement:'top'}">

但是,再次说明,根据 UX 指南,默认和推荐的行为是将应用栏放在底部,因为顶部栏留给了导航命令。

在前面的示例中,我们已经将应用栏添加到了主页面default.html,但实际上我们应该选择包含我们应用栏的页面并不是随意的,它取决于其范围,如下所述:

  • 如果应用栏包含全局命令,并且应该对所有页面可用,请将其添加到default.html页面。

  • 如果某个页面(一个PageControl对象)包含特定于该页面的命令,并且与其他页面不同,那么请将应用栏添加到该页面。

另外,我们可以在主default.html文件中定义一个默认应用栏,然后在该特定页面的加载事件上对应用栏进行所需的修改,这需要与默认命令不同的命令。

总结

在本章中,我们了解了应用栏是什么以及我们可以在哪里放置应用的命令和控件。我们还学习了应用栏和导航栏之间的区别。我们看到了应用栏命令是什么以及它们可以持有的不同选项。然后,我们看到了如何创建一个包含命令和分隔符的简单应用栏。

最后,我们了解了如何向应用栏上的任何命令类型添加基本功能。

在下一章,我们将到达 Windows Store 应用的最终目的地;那就是,提交到商店本身,我们将学习如何从 Visual Studio 将应用发布到商店,并在仪表板上处理应用配置。

第十章:打包和发布

Windows Store 就像一个大型购物中心,你的应用一旦发布到商店,就会像购物中心里的一家小店;Windows Store 仪表板是你将为店铺设置所有品牌、广告和营销材料的地方。Visual Studio 是你的生产环境,商店是你的目的地,两者之间的所有内容都在 Windows Store 仪表板中。在本章中,我们将介绍商店,并学习如何使应用通过所有阶段进入发布。同时,我们还将了解如何在 Visual Studio 内部与商店进行交互。

介绍 Windows Store

开发 Windows Store 应用不仅仅是关于设计、编码和标记。导致应用成功的非常关键的一个过程是在 Windows Store 仪表板上完成的。这里是提交应用、为应用铺平市场道路以及监控其在市场上表现的地方。同时,你也可以在这里获取关于你现有应用的所有信息,并计划你的下一个应用。我们在第八章用户登录中已经预览了仪表板,当时我们学习了如何添加认证和登录功能。提交过程分为七个阶段,在第八章用户登录中,我们在发布概要页完成了第一步,即预留一个应用名称并向 Windows Store 注册应用。为了提交应用以进行认证,还有六个步骤需要完成。如果你还没有打开一个 Windows Store 开发者账户,现在就是打开它的时候,因为你需要它来访问你的仪表板。在注册之前,确保你有一张信用卡。即使你有 entitles you to a free registration 的注册码,Windows Store 也要求使用信用卡来开设开发者账户。

登录后,在主页面进行中的应用部分找到你的应用,并点击编辑。这将引导你到发布概要页,应用将被命名为AppName: 发布 1。每次为同一应用提交新版本时,发布编号将自动递增。发布概要页列出了为你的应用准备 Windows Store 认证的步骤。在这个页面上,你可以输入关于你的 Windows Store 应用的所有信息,并上传其用于认证的包。此刻,你将注意到页面底部的两个按钮,分别为查看发布信息提交应用以进行认证,目前这两个按钮是禁用的,并且除非之前的所有步骤都标记为完成,否则它们将保持禁用状态。提交进度可以随时保存,以便以后继续,所以这不一定是一次性的任务。我们将逐一介绍这些步骤:

  1. 应用名称:这是第一步,包括为应用预留一个独特的名称。

  2. 销售详情:此步骤包括选择以下内容:

    • 应用程序价格层:此选项设置应用程序的价格(例如,免费或 1.99 美元)。

    • 免费试用期:这是客户可以在开始支付使用费用之前使用应用程序的天数。只有当应用程序价格层设置为免费时,此选项才启用。

    • 市场:在这里,你可以选择你希望应用程序在 Windows 商店中列表的市场。请注意,如果你的应用程序不是免费的,你的开发者账户必须为每个你选择的 国家/地区拥有有效的税务档案。

    • 发布日期:此选项指定了应用程序在 Windows 商店中列表的最早日期。默认选项是应用程序一旦通过认证就立即发布。

    • 应用程序类别和子类别:此选项表明你的应用程序将在商店中列出,进而将应用程序列在类别下。

    • 硬件要求:此选项将指定 DirectX 功能级别的最低要求以及系统 RAM。

    • 可访问性:这是一个复选框,当选中时,表示应用程序已经过测试,符合可访问性指南。

  3. 服务:在这一步,你可以向你的应用程序添加服务,比如 Windows Azure 移动服务和 Live 服务(正如我们在第八章,用户登录中所做的那样)。你还可以提供客户可以在应用程序内购买的产品和功能,称为应用内购买。

  4. 年龄分级和评级证书:在这一步,你可以从可用的 Windows 商店年龄分级中为应用程序设置一个年龄分级。另外,如果你的应用程序是一款游戏,你还可以上传特定于国家/地区的评级证书。

  5. 加密学:在这一步,你需要指定你的应用程序是否调用、支持并包含或使用密码学或加密。以下是一些应用程序可能应用密码学或加密的示例:

    • 使用数字签名,如身份验证或完整性检查。

    • 对您的应用程序使用或访问的任何数据或文件进行加密。

    • 密钥管理、证书管理或与公钥基础设施交互的任何内容

    • 使用诸如 NTLM、Kerberos、安全套接字层SSL)或传输层安全TLS)等安全通信通道。

    • 对密码或其他信息安全形式进行加密。

    • 版权保护或数字版权管理DRM)。

    • 防病毒保护

  6. :在这一步,你可以通过上传在 Visual Studio 中创建包过程中创建的.appxupload文件,将应用程序上传到商店。我们很快就会看到如何创建一个应用程序包。最新的上传将在发布摘要页的包框中显示,并应标记为验证完成

  7. 描述:在此步骤中,您可以添加一个简要描述(必填)您的应用程序为客户做什么。描述有 10,000 个字符的限制,并将显示在应用程序列表在 Windows Store 中的详情页面。除了描述之外,此步骤还包括以下功能:

    • 应用功能:此功能为可选。它允许您列出应用程序的最多 20 个关键功能。

    • 截图:此功能为必填项,需要提供至少一张.png文件图片;第一张可以是代表您应用程序的图形,但所有其他图片必须是带有标题的直接从应用程序中截取的屏幕快照。

    • 备注:此功能为可选。输入您认为客户需要知道的其他信息;例如,更新中的变化。

    • 推荐硬件:此功能为可选。列出应用程序运行所需的硬件配置。

    • 关键词:此功能为可选。输入与应用程序相关的关键词,以帮助其在搜索结果中出现。

    • 版权和商标信息:此功能为必填项。输入将在应用程序列表页面向客户展示的版权和商标信息。

    • 其他许可条款:此功能为可选。输入任何对标准应用程序许可条款的更改,客户在获取此应用程序时需要接受。

    • 推广图片:此功能为可选。添加编辑用于在商店中展示应用程序的图片。

    • 网站:此功能为可选。如果有的话,输入描述应用程序的网页 URL。

    • 支持联系方式:此功能为必填项。输入支持联系的电子邮件地址或网页 URL,您的客户可以通过该地址寻求帮助。

    • 隐私政策:此功能为可选。输入包含隐私政策的网页 URL。

  8. 给测试人员的备注:这是最后一步,包括添加关于此特定版本的备注,给那些将从 Windows Store 团队审查您应用程序的人。这些信息将帮助测试人员理解和使用此应用程序,以便快速完成测试并为您应用程序在 Windows Store 进行认证。

每个步骤将保持禁用状态,直到完成前一个步骤,并且正在进行中的步骤会被标记上大约需要完成的时间(分钟)。每当一个步骤的工作完成时,在摘要页面上会标记为已完成,如下面的屏幕快照所示:

Windows Store 简介

提交应用程序以进行认证

在所有步骤都被标记为完成后,您可以提交应用程序进行认证。一旦您点击“提交以进行认证”,您将收到电子邮件通知,Windows 商店已经收到了您的应用程序进行认证。仪表板将提交应用程序,然后会将您引导到“认证状态”页面。在那里,您可以在应用程序进行认证过程中查看其进度,包括以下步骤:

  • 预处理:这一步将检查您是否已经输入了所有发布应用程序所需的必要详细信息。

  • 安全测试:这一步将您的应用程序测试是否含有病毒和恶意软件。

  • 技术合规性:这一步使用 Windows 应用程序认证工具包来检查应用程序是否符合技术政策。同样的评估可以在本地使用 Visual Studio 运行,我们稍后会看到,在您上传包之前,可以进行此评估。

  • 内容合规性:这一步由商店团队的质量保证人员完成,他们会检查应用程序中的内容是否符合由微软制定的内容政策。

  • 发布:这一步涉及发布应用程序;除非您在销售详情中指定的发布日期是未来的,否则这个过程不会花费太多时间,在这种情况下,应用程序将保持在这个阶段直到那个日期到来。

  • 签名和发布:这是认证过程的最后一步。在这个阶段,您提交的包将使用与您开发者账户技术细节相匹配的可信证书进行签名,从而向潜在的客户和观众保证该应用程序已通过 Windows 商店认证。

下面的屏幕快照显示了在 Windows Store 仪表板上的认证过程:

提交应用程序进行认证

无需在那页等待;您可以点击“前往仪表板”按钮,您将被重定向到“我的应用”页面。在包含您刚刚提交的应用程序的框中,您会注意到“编辑”和“删除”链接已经消失,取而代之的只有“状态”链接,它将带您到“认证状态”页面。此外,这个页面将出现一个“通知”部分,并列出关于您刚刚提交的应用程序的状态通知,例如:

BookTestApp: 发布 1 版已提交进行认证。6/4/2013

当认证过程完成后,您将通过电子邮件收到通知。同时,在仪表板的主页上将添加一个通知,显示认证的结果,无论是失败还是成功,并带有指向认证报告的链接。如果应用程序失败,认证报告将显示需要重新审查的部分。此外,还有一些资源可以帮助您在认证过程中识别和修复可能出现的问题和错误;这些资源可以在以下位置找到:Windows Dev Center 页面的 Windows Store 应用程序部分:

msdn.microsoft.com/en-us/library/windows/apps/jj657968.aspx

此外,您随时可以通过仪表板检查应用在认证过程中的状态。

成功完成认证过程后,应用包将被发布到商店,其中包含所有相关数据,这些数据将显示在您的应用列表页面上。用户可以通过这个页面访问数百万 Windows 8 用户,他们可以找到、安装和使用您的应用。

一旦应用被发布到商店并且运行正常,您就可以开始收集遥测数据,了解它在商店中的表现;这些指标包括应用被启动的次数、运行时间以及是否发生崩溃或遇到 JavaScript 异常。一旦您启用了遥测数据收集,商店就会为您应用检索这些信息,分析它们,并在您仪表板上的非常具有信息性的报告中总结它们。

现在我们已经涵盖了将您的应用提交到 Windows 商店所需了解的几乎所有内容,让我们看看在 Visual Studio 中需要做些什么。

Visual Studio 中的商店

您可以通过商店菜单从 Visual Studio 内部访问 Windows 商店。并非我们仪表板上完成的所有事情都可以在这里完成;创建应用包等一些非常重要的功能是由此菜单提供的。在 Visual Studio 2012 Ultimate 中,商店菜单位于菜单栏下的项目项下,如果您使用的是 Visual Studio 2012 Express,则可以直接在菜单栏中找到它,仅当您在 Windows 商店项目或解决方案上工作时,它才会出现。

我们将详细查看商店菜单提供的命令,以下屏幕截图展示了菜单的外观:

Visual Studio 中的商店

商店菜单中的命令选项如下:

  • 打开开发者账户...:此选项将打开一个网页,引导您前往Windows 开发者中心,以获取 Windows 商店应用的开发者账户。

  • 保留应用名称...:此选项将引导您前往 Windows 商店仪表板,并具体指向提交应用页面,您可以开始第一步,即保留我们之前在第八章中看到的签名用户一节中提到的应用名称。

  • 获取开发者许可证...:此选项将打开一个对话窗口,提示您使用您的 Microsoft 账户登录;登录后,如果您的账户已经有许可证,它将检索或续签您的开发者许可证。

  • 编辑应用清单:此选项将打开带有清单设计器的标签页,以便您可以编辑应用清单文件中的设置。

  • 将应用与商店关联...:此选项将在 Visual Studio 中打开一个类似向导的窗口,其中包含将应用与商店关联所需的步骤。第一步将提示您登录;之后,向导将检索您用于登录的 Microsoft 帐户注册的应用。选择一个应用,向导将自动将以下值下载到本地计算机上当前项目的应用清单文件中:

    • 包的显示名称

    • 包的名称

    • 发布者 ID

    • 发布者的显示名称

  • 捕获屏幕截图...:此选项将构建当前的应用程序项目并在模拟器中启动,而不是在启动屏幕上。一旦模拟器打开,你可以在模拟器侧边栏上使用复制屏幕截图按钮。这个按钮将用于捕获正在运行的应用程序的屏幕截图,并将其保存为.png文件。

  • 创建应用包...:此选项将打开一个包含创建应用包向导的窗口,我们稍后会看到。

  • 上传应用包...:此选项将打开一个浏览器,如果您设置了 Store 账户并且注册了应用,它将引导您到 Windows Store 仪表板的发布摘要页面。否则,它只会带您到登录页面。在发布摘要页面,您可以选择,并从那里上传您的应用包。

创建应用包

商店菜单中,最实用的工具之一是应用包创建,它将构建并创建一个我们可以稍后上传到商店的应用包。这个包包含了商店所需的所有与应用和开发者特定的详细信息。此外,开发者不必担心整个包创建过程的复杂性,这一切都为我们抽象化,并通过一个向导链接窗口提供。

创建应用包向导中,我们可以直接为 Windows 商店创建应用包,或者创建用于测试或本地分发的应用包。此向导将提示您为应用包指定元数据。

以下屏幕截图显示了此过程的前两个步骤:

创建应用包

在第一步中,向导将询问您是否想要构建上传到 Windows 商店的包;如果您想为商店构建包,请选择,如果您想为测试和本地使用构建包,请选择。考虑第一种情况,点击登录以继续并使用您的 Microsoft 帐户完成登录过程。

成功登录后,向导将提示您选择应用名称(前一个屏幕的步骤 2), either by clicking on the apps listed in the wizard or choosing the Reserve Name link that will direct you to the Windows Store Dashboard to complete the process and reserve a new app name. The following screenshot shows step 3 and step 4:

创建应用包

第 3 步包含选择和配置包部分,在这一部分我们将选择输出位置,它指的是包文件将被创建的地方。此外,在这一部分我们还可以为这个包输入一个版本号,或者选择使其每次打包应用时自动递增。此外,我们还可以从通用ARMx64x86选项中选择我们希望为包设置的构建配置,默认情况下,将选择当前活动项目平台,并为所选的每个配置类型生成一个包。

本节最后的选项是包括公共符号文件。选择此选项将生成公共符号文件(*.pdb)并添加到包中,这将帮助商店后来分析你的应用,并将用于映射你的应用崩溃。最后,点击创建,等待包装处理完成。完成后,出现包创建完成部分(第 4 步),并将显示输出位置作为一个链接,将引导你到包文件。此外,还有一个直接启动Windows 应用认证工具包的按钮。Windows 应用认证工具包将根据商店要求验证应用包并生成验证报告。

下面的屏幕截图显示了包含Windows 应用认证工具包过程的窗口:

创建应用包

另外,还有一种创建应用包的第二种场景,但更多的是针对测试,除了在向导的第一页必须选择,且不需要使用 Microsoft 账户登录之外,与刚刚看到的流程完全相同。这种选项将在包创建完成后结束向导并显示输出文件夹的链接,但你将无法启动Windows 应用认证工具包。使用这种选项创建的包只能在与安装了开发者许可证的计算机上使用。由于商店的包最好先在本地测试,所以这种场景会经常使用。在为测试或本地分发创建应用包之后,你可以在本地计算机或设备上安装它。

让我们在本地安装这个包。启动创建应用包向导;在第一步选择,完成向导,然后在指定包位置的输出文件夹中找到刚刚创建的应用包文件。将此文件夹命名为PackageName_Test。这个文件夹将包含一个.appx文件、一个安全证书、一个 Windows PowerShell 脚本和其他文件。与应用包一起生成的 Windows PowerShell 脚本将用于测试安装包。导航到输出文件夹并安装应用包。定位并选择名为Add-AppDevPackage的脚本文件,然后右键点击,选择以 PowerShell 运行,如下图所示:

创建应用包

运行脚本后,它将执行以下步骤:

  1. 它显示有关执行策略更改的信息,并询问是否更改执行策略。输入Y以继续。

  2. 它检查你是否拥有开发者许可证;如果没有脚本,它会提示你获取一个。

  3. 它检查并验证应用包和所需证书是否已存在;如果缺少任何项目,你将在安装开发包之前被通知安装它们。

  4. 它检查并安装任何依赖包,如WinJS库。

  5. 它显示消息成功:您的包已成功安装

  6. 按下Enter键继续,窗口将关闭。

上述步骤显示在以下屏幕截图中:

创建应用包

一旦脚本成功完成,你可以在开始屏幕上寻找你的应用并启动它。

提示

请注意,对于那些位于网络中且没有权限访问Add-AppDevPackage PowerShell 脚本文件所在目录的用户,可能会出现错误信息。这个问题可以通过在运行脚本之前将output文件夹的内容复制到本地机器来简单解决。另外,对于任何安全相关的问题,你可能需要咨询 Windows 开发者中心以获取解决方案。

总结

在本章中,我们了解了 Windows 商店仪表板的所有细节,并涵盖了将应用提交到商店的步骤。我们还学习了 Visual Studio 中的商店菜单以及它提供的与仪表板交互的选项。此外,我们还学习了如何创建应用包以及如何将应用本地下载以供测试。

在下一章中,我们将窥视硬币的另一面,使用 XAML 开发 Windows 8 应用,并了解它与使用 JavaScript 开发应用的相似之处,从而向您展示使用多种编程语言开发 Windows 8 应用的力量。

第十一章:使用 XAML 开发应用程序

开发 Windows 商店应用程序不仅限于 HTML5 和 JavaScript。微软提供了使用可扩展应用程序标记语言(XAML)和.NET 的其他选择,从而将更广泛的开发者和专业知识吸引到商店开发。无论你的背景如何,是网页还是 Windows 开发,都有一个适合你的地方——一个起点——因为无论你选择哪种编程语言,通往 Windows 商店的道路都是一样的。在前几章中,我们学习了如何使用 HTML5 和 JavaScript 开发应用程序和功能。但在本章中,我们将学习其他平台和编程语言,以及使用 XAML/C#创建应用程序的基础知识。

使用不同平台创建应用程序

Windows 8 最重要的进步之一是,你可以使用多种框架和编程语言开发应用程序,面向网页和 Windows 开发者。此外,开发者可以构建并利用他们现有的编程技能和知识来创建 Windows 商店应用,不一定需要掌握一套全新的技能。

网页开发者将能够利用他们的 HTML5、CSS3 和 JavaScript 技能,甚至可以轻松地将现有网站移植到商店应用中,而熟悉微软.NET 框架和 Silverlight 的 Windows 开发者可以运用他们的 XAML、C#和 Visual Basic 技能付诸实践。此外,Windows 8 针对熟悉 C++语法和本地库的开发者,通过提供使用 Visual C++/XAML 创建 Windows 商店应用的机会。而且,使用 C++,你可以创建 Direct2D 和 Direct3D 应用。总之,我们有 XAML 标记和 C#、VB.NET、C++,更不用说,Visual Studio 2012 为所有这些编程语言提供了项目模板和 Intellisense 支持。

同一个应用程序可以用 XAML 或 HTML5 来构建,部署和运行时,两个版本将以相同的方式运行。我们在前面的章节中学到的所有用 JavaScript 和 HTML5 为 Windows 商店应用程序编写的功能和特性,都可以用 C#、VB.Net 和 XAML 来实现。选择使用哪种编程语言是基于个人喜好、背景经验以及语言熟悉度,而不是其他因素。两种选择都需要一定的学习水平。熟悉 HTML 标记、使用 CSS 进行样式设计和使用 JavaScript 实现功能的网页开发者,需要学习 WinJS 特定的 JavaScript 函数和 HTML 数据属性及类。此外,有 XAML 经验的开发者会发现与 WPF 和 Silverlight 有很多相似之处,但需要学习为 Windows 商店设计和功能开发。然而,如我所说,当你从熟悉的领域开始 Windows 商店开发时,学习曲线是最小的。

介绍 XAML 应用程序

使用 XAML 开发的 Windows 商店应用的路线图与使用 JavaScript 开发的商店应用相同,从工具开始,通过设计指南获取开发者许可证,规划应用,最后进行打包并将应用发布到商店。

让我们使用 XAML 创建一个基本的 Windows 商店应用,并将其与使用 HTML5 创建的应用进行比较。在 Visual Studio 中,从顶部菜单,导航到 文件 | 新建项目。在 新建项目 对话框中,从左侧窗格下的 已安装 | 模板 中选择您喜欢的编程语言,然后选择 Windows 商店。接下来,我们选择一个列表中的 Windows 商店应用项目模板,并在 名称 文本框中为其输入一个名字。我将为这个演示选择 Visual C#;您也可以选择 Visual BasicVisual C++。最后,点击 确定 创建项目:以下屏幕快照显示了刚刚讨论的过程:

介绍 XAML 应用

前一个屏幕快照显示了随 XAML 提供的以下 Windows 商店应用模板:空白应用 (XAML)网格应用 (XAML),以及分割应用 (XAML)

  • 空白应用 (XAML):此模板提供了一个空的 Windows 商店应用,它可以编译并运行,但其中没有用户界面控件或数据。当基于这个模板运行一个应用时,它将只显示一个包含占位符文本的黑屏。

  • 网格应用 (XAML):此模板提供了一个应用,使用户能够浏览不同的分类,并深入查看每个分类下的内容细节。此模板的好例子包括购物应用、新闻应用以及图片或视频应用。网格应用 (XAML) 模板从一块着陆主页开始,该主页将展示一系列组或分类。一个单独的组是一组命名项的集合;例如,一组名为“体育新闻”的新闻文章。当用户选择一个组时,应用将打开组详情页,该页面的右侧将显示该组包含的项列表。因此,当用户在主页或组详情页上选择一个单独的项时,应用将打开一个显示项详情的页面。

    以下屏幕快照显示了网格应用 (XAML) 的示例主页:

    介绍 XAML 应用

  • 分栏应用(XAML):此模板提供了一个允许用户浏览类别以找到特定内容的应用,与网格应用(XAML)模板类似;然而,使用分栏应用(XAML)模板,用户可以在同一页面的双栏分隔视图中查看项目列表和项目详细信息。这种分隔视图允许所有用户快速切换项目。此模板的使用示例包括新闻阅读器或电子邮件应用。此模板从显示组列表的起始主页开始,当用户选择一个组时,应用将打开一个分隔视图页面。下面的屏幕截图显示了一个示例分隔视图页面:介绍 XAML 应用

这三个项目模板与 Windows 商店 JavaScript 项目中提供的模板类似,但后者提供了两个额外的模板,分别是固定布局应用导航应用

我们将从空白应用(XAML)模板开始,该模板包含了运行应用所需的最小项目文件。空白应用(XAML)模板创建了一个空的 Windows 商店应用,其中没有用户界面,但可以编译并运行。创建空白应用后,导航到 Visual Studio 右侧的解决方案资源管理器,展开项目文件列表,以查看与此模板一起创建的默认文件。

下面的屏幕截图显示了解决方案资源管理器右侧的内容和打开在 XAML 文本编辑器中的MainPage.xaml文件,位于左侧:

介绍 XAML 应用

我们刚刚创建的项目包含以下必需的文件夹和文件,这些文件对于所有使用 C#或 Visual Basic 的 Windows 商店应用来说是不可缺少的:

  • Properties:此文件夹包含应用程序汇编信息。

  • References:此文件夹包含项目引用文件,默认情况下,有以下两个 SDK 引用:.NET 用于 Windows 商店应用Windows

  • Assets:此文件夹包含以下图像:

    • 分别尺寸为 150 x 150 像素和 30 x 30 像素的大和小 logo 图像。

    • SplashScreen 图像。

    • 尺寸为 50 x 50 像素的商店 Logo图像。

  • Common:此文件夹包含应用中的常用共享资源,如StandardStyles.xaml文件,该文件提供了一组默认样式,赋予了应用 Windows 8 的外观和感觉。此外,此文件夹还将包含实用工具和帮助器类的文件。

此模板还包括以下.xaml页面文件:

  • App.xaml:这是必需的主要应用文件,用于显示用户界面,在应用运行时首先加载。此页面声明了跨整个应用共享的资源,如样式,并为内容宿主提供标记。这个页面类似于在使用 JavaScript 的应用中default.html页面所代表的内容。

  • App.xaml.cs:这是App.xaml的代码隐藏文件,包含处理全局应用特定行为和事件的代码,例如应用的启动和挂起。这个文件与使用 JavaScript 的 app 中的default.js文件类似。

  • MainPage.xaml:这是应用的默认启动页面,并包含实例化页面的最小 XAML 标记和代码。

  • MainPage.xaml.cs:这是与MainPage.xaml文件对应的代码隐藏文件。

最后,还有Package.appxmanifest这个清单文件,它包含了与 JavaScript 模板中相同的应用程序描述和设置。

注意

微软建议不要删除Common文件夹中的文件。此外,它也不能重命名或修改,因为这会导致构建错误。如果需要修改这些文件,你可以创建原始文件的副本并进行修改。

那些之前没有听说过 XAML 的人可能会对刚才在应用和MainPage.xaml文件中看到的语法感到困惑。XAML 基于 XML 构建了一套基本的语法。当剥离掉冗余的部分,一个 XAML 文件就是一个显示对象之间层次关系的 XML 文档,并且为了被认为是有效的,它也必须是一个有效的 XML 文档。XAML 文件有一个.xaml文件扩展名,每个 XAML 文件都与其一个代码隐藏文件相关联,这个代码隐藏文件包含处理事件、操作在 XAML 中创建或声明的对象和 UI 元素的代码。代码隐藏文件与 XAML 页面的部分类结合构成了一个完整的类。这与 ASP.NET 网页的概念类似,.aspx文件包含标记和代码隐藏文件,后缀为.cs.vb。此外,XAML 文件可以在 Microsoft Expression Blend 中打开和编辑。如果你是 XAML 的新手,不必太担心语法,因为 Visual Studio 会通过提供自动完成提示和建议列表来帮助你编写有效的标记,你会在学习过程中了解语法。

使用 XAML 标记,我们可以像使用 HTML 一样创建 UI 元素,但语法有所不同。让我们在MainPage.xaml文件中的Grid元素内使用以下语法添加以下 UI 元素:

<TextBlock x:Name="pageTitle" Text="Test XAML App" ></TextBlock>
<TextBox Text="Input text here..." />
<CheckBox Content="Yes"/>

前面的代码列表显示了以下属性:x:Name,它指定了分配给TextBlock元素的名称;Text,它指定了作为文本的数据,将填充此元素;Content,它与Text类似,但指定作为文本的数据,将显示在CheckBox元素的旁边。

代码列表中的第一行声明了一个基本的TextBlock元素,它与 HTML 中的label元素类似。我们给这个元素一个名字,并为其Text属性输入一个值。第二个元素是Textbox,带有Text值,第三个元素是一个带有Content值的Checkbox元素。您可以手动编写语法,也可以从工具箱面板中选择一个控件,并将其直接拖到 XAML 文本编辑器或设计表面,这两个都在分屏视图中可见。

在设计窗口中,您可以操作这些 UI 控件,并按照以下屏幕截图所示安排它们在窗口中的位置:

介绍 XAML 应用

您会注意到,在设计面板中操作控件会在下方的XAML面板中反映出来,因为正在为元素设置新的属性并更改现有的属性。如果您现在运行应用程序,您将看到一个包含我们刚刚添加到MainPage.xaml文件中的三个元素的黑色屏幕。

MainPage.xaml文件包含运行页面所需的最小标记和代码,但缺少所有实现 Windows Store 应用重要功能的附加代码和类,例如适应用户界面变化和处理应用程序的不同状态。幸运的是,Visual Studio 提供的其他页面模板,例如基本页面模板,包含了帮助您实现这些功能的代码和帮助类。为此目的,我们通常在处理空白应用程序(XAML)项目时,将那个空的MainPage模板替换为其他页面模板之一。要替换MainPage.xaml文件,请在解决方案资源管理器中右键点击它,然后点击删除。然后,在项目根节点上右键点击,点击添加新项目项,这将打开一个对话框窗口。从那里,在下拉列表中选择Visual C#(或如果您在示例开始时选择了不同的模板,选择 Visual Basic)下的Windows Store模板类型。接下来,选择基本页面,并将其命名为MainPage.xaml,否则项目将无法正确构建。以下屏幕截图说明了该过程:

介绍 XAML 应用

然后,点击添加。如果这是您第一次将不同于空白页面模板的新页面添加到空白应用(XAML)模板中,将会显示一个带有警告的消息对话框,内容为此添加依赖于项目中缺失的文件。点击以自动添加缺失的文件。此页的 XAML 和代码后置文件被添加到项目中,如果您展开Common文件夹,会发现原本只包含一个文件StandardStyles.xaml的文件夹现在包含了包含多个帮助器和实用类别的代码文件。新添加的页面在您构建项目/解决方案之前不会在设计器中显示,因此它会编译页面依赖的帮助类。让我们看看这次更改后应用的样子;按F5以构建并在调试模式下运行应用。

运行后,应用将显示为一个黑色屏幕,包含标题我的应用,如下图所示:

介绍 XAML 应用

这里需要注意的是,此页面默认符合 Windows 8 的设计指南,而我们无需添加任何样式或标记。正如你所看到的,标题似乎是相同的字体大小,并且按照Windows 8 应用商店应用的 Windows 8 UX 指南页面中指定的确切边距进行定位:(www.microsoft.com/en-in/download/details.aspx?id=30704)。

添加标题、主题颜色和内容

让我们通过添加标题并更改其主题颜色来修改这个最小应用。然后,我们将添加一个简单的文本,并编写一些代码来处理基本按钮点击事件。

  1. 要更改此应用的标题,请执行以下步骤:

    1. 打开MainPage.xaml文件。

    2. XAML设计面板中,选择标题我的应用,然后右键点击选择编辑文本,或者在属性窗口下Common中更改Text属性。如果默认情况下没有显示,属性窗口应该位于 Visual Studio 左侧,低于解决方案资源管理器面板。

  2. 要更改此应用的主题颜色,请执行以下步骤。与使用 JavaScript 的应用程序类似,我们也可以在这里切换深色和浅色主题。在 JavaScript 应用程序中,default.html页面引用了两个 CSS 文件,ui-dark.cssui-light.css。在 XAML 应用程序中,在App.xaml文件中如下进行主题切换:

    1. 打开App.xaml文件。

    2. 转到<Application>标签并在闭合标签之前添加RequestedTheme属性。

    3. 在标签的引号内点击,Visual Studio 的 Intellisense 将提示您两个属性值:LightDark。选择Light<Application>标签将如下所示:

      <Application
      x:Class="App1.App"
      
         RequestedTheme="Light">
      
    4. 运行应用以查看差异。

  3. 现在要添加一些 UI 内容,打开MainPage.xaml文件,定位根Grid元素和它内部的<VisualStateManager.VisualStateGroups>标签。在这个标签之前添加以下 XAML 代码片段:

    <StackPanel Grid.Row="1" Margin="120,30,0,0">
      <TextBlock Text="Is this your first XAML App?"/>
      <StackPanel Orientation="Horizontal" Margin="0,20,0,20">
        <TextBox x:Name="answerInput" Width="360"HorizontalAlignment="Left"/>
        <Button Content="Post My Answer"/>
      </StackPanel>
      <TextBlock x:Name="myAnswer"/>
    </StackPanel>
    

    上述 XAML 代码声明了一个StackPanel控件,该控件内部包含 UI 控件(可以把它想象成一个div元素)。在这个控件内部,我们添加了一个TextBlock元素并为其Text属性赋值,然后我们在父级StackPanel控件内嵌套了一个StackPanel控件(一个div内的div元素)。这个StackPanel元素将包含两个控件:一个TextBox元素用于输入我们为其widthHorizontalAlignment属性赋值的输入值,以及一个Button控件,我们为其Content属性赋值。最后,在内部StackPanel元素的外部添加另一个空的TextBlock元素。

    运行应用程序,它将看起来像以下屏幕快照:

    添加标题、主题颜色和内容

  4. 最后,让我们通过为在标记中声明的按钮添加事件处理程序来添加一些功能,具体步骤如下:

    1. 在 XAML 设计器或文本编辑器中点击发布我的答案按钮,它将在属性窗口中显示。

    2. 属性窗口中,定位并点击左上角的事件按钮。

    3. 在列表顶部找到Click事件,双击或在文本框中按Enter键。

    这将创建事件处理方法。在文件MainPage.xaml.cs的代码编辑器中显示它。

    以下屏幕快照显示了该过程:

    添加标题、主题颜色和内容

    自动生成的事件处理程序名字为Button_Click(如果按钮有一个为其name属性赋值,事件处理程序看起来可能像ButtonName_Click)。该方法将如下所示:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
    }
    

    让我们添加一些简单的代码,获取输入文本框中输入的文本并在名为myAnswer的空TextBlock中显示它。代码将如下所示:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
      myAnswer.Text = answerInput.Text;
    }
    
    

    如果我们回到 XAML 编辑器,我们会看到Click事件处理程序已经这样添加到了Button元素中:

    <Button Content="Post My Answer" Click="Button_Click"/>
    

    现在,运行应用程序,在文本框中输入一些文本,并测试按钮。点击后,它将在屏幕上显示文本框内的任何内容。

XAML 的魅力远不止这个简单的演示,之前的例子仅仅展示了我们如何从一个非常基础的应用程序开始,逐步构建内容和功能。一旦我们熟悉了 XAML,它并不那么难;与其他编程语言一样,我们需要进行实践。然而,选择 XAML 还是 HTML5 完全取决于你。

使用 XAML 开发 Windows Store 应用的一个优点是,您可以使用微软提供的指南将Windows Phone 7应用迁移到 Windows 8。同样,微软也提供了一个指南,帮助您将现有的 Silverlight 或 WPF/XAML 代码通过 XAML 转换为 Windows Store 应用。这两个指南都可以在Windows Phone Dev Center页面找到(developer.windowsphone.com/en-us)。

总结

在本章中,我们了解到了 Windows 8 为开发者提供的不同选择。此外,我们还介绍了 Windows Store 应用中的 XAML 语言和语法。

我们还介绍了如何使用 XAML 开始开发 Windows Store 应用,以及它与使用 JavaScript 开发的不同之处,这让我们对使用任一语言开发有了预期。

最后,我们创建了一个最小的应用,并向其添加了一些基本的 UI 内容和功能,使用了 XAML 标记语言。

在这本书中,我们介绍了 HTML5 和 CSS3 的新特性,并学习了这些特性如何在 Windows Store 应用中实现。我们还介绍了专为 Windows Store 应用设计的 JavaScript 控件功能。之后,我们学习了如何创建一个基本的 JavaScript 应用,以及如何使用 JavaScript 快速开始开发 Windows Store 应用。进一步地,我们了解了一些应用的重要特性以及如何实现这些特性。我们首先通过 WinJS 控件检索和显示数据。然后,我们介绍了应用的视图状态以及如何使应用响应这些视图状态的变化。之后,我们了解了 Windows 8 中的磁贴,并学习了如何添加动态磁贴并向应用发送通知。此外,我们还学习了如何将应用与 Windows Live 服务集成,以使用户能够使用他们的电子邮件账户进行认证和登录。我们还学习了 Windows Store 应用中的应用栏以及如何向其添加按钮。最后,我们介绍了 Windows Store,并学习了有关将应用打包并发布到商店的所有内容。

posted @ 2024-05-23 14:42  绝不原创的飞龙  阅读(17)  评论(0编辑  收藏  举报