快速入门:添加 SemanticZoom (HTML)
[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]
了解如何使用 SemanticZoom 控件在同一内容的两个视图之间缩放。
先决条件
- 我们假设你可以创建使用 JavaScript 的基本 Windows 应用商店应用,该应用使用 Windows JavaScript 库控件。有关如何开始使用 WinJS 控件的说明,请参阅快速入门:添加 WinJS 控件和样式。
- 为了按照本快速入门操作,需要了解如何使用 ListView 控件。有关 ListView 控件的入门帮助,请参阅快速入门:添加 ListView。
- 若要使用 SemanticZoom 控件,需要了解如何创建分组的 ListView。有关详细信息,请参阅如何对 ListView 中的项进行分组。
什么是 SemanticZoom 控件?
SemanticZoom 控件可使用户在同一内容的两个不同视图之间切换。其中一个是内容的主视图。第二个视图是相同内容以不同方式呈现的视图,它使用户可以快速在其中导航。例如,查看通讯簿时,用户可以放大一个字母,查看与该字母关联的名称。
若要提供此缩放功能,SemanticZoom 控件使用另外两个控件:一个控件提供放大视图,另一个控件提供缩小视图。
<div data-win-control="WinJS.UI.SemanticZoom">
<!-- The control that provides the zoomed-in view goes here. -->
<!-- The control that provides the zoomed-out view goes here. -->
</div>
这些控件可以是实现 IZoomableView 接口的任意两个控件。WinJS 提供用于实现 IZoomableView 接口的控件:ListView 控件。本快速入门中的示例展示如何使用带有两个 ListView 控件的 SemanticZoom。
不要将语义上的缩放与光学缩放混淆。尽管它们的交互和基本行为(基于缩放比例显示更多或更少细节)一致,但是光学缩放是指调整内容区域或对象(如照片)的放大倍数。
创建你的数据
若要使用 SemanticZoom,需要一个包含分组信息的 IListDataSource。 创建 IListDataSource 的一种方式是创建 WinJS.Binding.List。每个 WinJS.Binding.List 有一个 dataSource 属性,该属性返回一个包含你的数据的 IListDataSource。
在你的项目中添加新的 JavaScript 文件以包括你的数据。将它命名为 "data.js"。
在刚创建的 data.js 文件中,创建将为你的 ListView 控件提供数据的基础数据源。以下示例根据 JSON 对象的一个数组 (myData) 创建一个 WinJS.Binding.List:
// Start of data.js (function () { "use strict"; var myData = [ { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png" }, { title: "Orangy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Orangy Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Absolutely Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Absolutely Orange", text: "Sorbet", picture: "images/60Orange.png" }, { title: "Triple Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Triple Strawberry", text: "Sorbet", picture: "images/60Strawberry.png" }, { title: "Double Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Double Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Double Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png" }, { title: "Green Mint", text: "Gelato", picture: "images/60Mint.png" } ]; // Create a WinJS.Binding.List from the array. var itemsList = new WinJS.Binding.List(myData);
注意 此数据指的是几个图像。要获取图像,请下载 ListView 分组和 SemanticZoom 示例,然后从示例复制图像到你的项中。你还可使用你自己的图像—,只需确保已更新了数据中的
picture
属性的值。提示
除了 WinJS.Binding.List,你还可以使用 StorageDataSource 或自定义 VirtualizedDataSource。有关创建自定义数据源的详细信息,请参阅如何创建自定义数据源。
创建一个包含分组信息的数据源版本。 如果你使用的是 WinJS.Binding.List,则可以调用它的 createGrouped 方法来创建 List 的分组版本。createGrouped 方法采用以下三个参数:
- getGroupKey:一个函数,在给出列表中的某个项目时,返回该项目所属的组密钥。
- getGroupData:一个函数,在给出列表中的某个项目时,返回代表该项目所属的组的数据对象。
- compareGroups:一个函数,对两个组进行比较,并在第一个组小于第二个组的情况下返回一个负值,在两个组相等时返回零,在第一个组大于第二个组时返回一个正值。
此示例使用 List.createGrouped 方法创建 List 的分组版本。它使用每个项的标题的第一个字母来定义组。
// Sorts the groups. function compareGroups(leftKey, rightKey) { return leftKey.charCodeAt(0) - rightKey.charCodeAt(0); } // Returns the group key that an item belongs to. function getGroupKey(dataItem) { return dataItem.title.toUpperCase().charAt(0); } // Returns the title for a group. function getGroupData(dataItem) { return { title: dataItem.title.toUpperCase().charAt(0) }; } // Create the groups for the ListView from the item data and the grouping functions var groupedItemsList = itemsList.createGrouped(getGroupKey, getGroupData, compareGroups);
使你的数据可以访问程序的其他部分。此示例使用 WinJS.Namespace.define 使分组的列表可公开访问。
WinJS.Namespace.define("myData", { groupedItemsList: groupedItemsList }); })(); // End of data.js
创建两个 ListView 控件
正如之前所述,SemanticZoom 控件需要其他两个用于实现 IZoomableView 接口的控件:一个用于提供放大的视图,另一个用户提供缩小的视图。
在将要包含 SemanticZoom 的 HTML 页面的 head 部分中,添加对上一步中创建的数据文件的引用。
<!-- Your data file. --> <script src="/js/data.js"></script>
为你的 ListView 对象定义 3 个模板:一个用于放大的项目视图、一个用于放大视图中的组标头,另一个用于缩小视图中的组标头。
<!-- Template for the group headers in the zoomed-in view. --> <div id="headerTemplate" data-win-control="WinJS.Binding.Template" style="display: none"> <div class="simpleHeaderItem"> <h1 data-win-bind="innerText: title"></h1> </div> </div> <!-- Template for the ListView items in the zoomed-in view. --> <div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none"> <div class="mediumListIconTextItem"> <img class="mediumListIconTextItem-Image" data-win-bind="src: picture" /> <div class="mediumListIconTextItem-Detail"> <h4 data-win-bind="innerText: title"></h4> <h6 data-win-bind="innerText: text"></h6> </div> </div> </div> <!-- Template for the zoomed out view of the semantic view. --> <div id="semanticZoomTemplate" data-win-control="WinJS.Binding.Template" style="display: none"> <div class="semanticZoomItem"> <h1 class="semanticZoomItem-Text" data-win-bind="innerText: title"></h1> </div> </div>
在 HTML 中,定义两个 ListView 控件。第一个控件提供放大的视图,而第二个控件提供缩小的视图。
- 将用于放大的 ListView 的 itemDataSource 设置为 myData.groupedItemList.dataSource,它是包含要显示的项目的 IListDataSource。将其 groupDataSource 设置为 myData.groupedItemsList.groups.dataSource,它是包含组信息的 IListDataSource。
- 对于缩小的 ListView,将其 itemDataSource 设置为 myData.groupedItemList.groups.dataSource,它是包含组信息的 IListDataSource。ListView 从该位置获取要显示的组标题。
该示例创建了两个 ListView 控件,并将其配置为使用你刚创建的模板。
<!-- The zoomed-in view. --> <div id="zoomedInListView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: myData.groupedItemsList.dataSource, itemTemplate: select('#mediumListIconTextTemplate'), groupHeaderTemplate: select('#headerTemplate'), groupDataSource: myData.groupedItemsList.groups.dataSource, selectionMode: 'none', tapBehavior: 'none', swipeBehavior: 'none' }" ></div> <!--- The zoomed-out view. --> <div id="zoomedOutListView" data-win-control="WinJS.UI.ListView" data-win-options="{ itemDataSource: myData.groupedItemsList.groups.dataSource, itemTemplate: select('#semanticZoomTemplate'), selectionMode: 'none', tapBehavior: 'invoke', swipeBehavior: 'none' }" ></div>
在你的 CSS 文件中,定义用于模板和 ListView 控件的样式。如果跳过该步骤,你的应用仍将运行,但它的外观会受到影响。
/* Template for headers in the zoomed-in ListView */ .simpleHeaderItem { width: 50px; height: 50px; padding: 8px; } /* Template for items in the zoomed-in ListView */ .mediumListIconTextItem { width: 282px; height: 70px; padding: 5px; overflow: hidden; display: -ms-grid; } .mediumListIconTextItem img.mediumListIconTextItem-Image { width: 60px; height: 60px; margin: 5px; -ms-grid-column: 1; } .mediumListIconTextItem .mediumListIconTextItem-Detail { margin: 5px; -ms-grid-column: 2; } /* Template for items in the zoomed-out ListView */ .semanticZoomItem { width: 130px; height: 130px; background-color: rgba(38, 160, 218, 1.0); } .semanticZoomItem .semanticZoomItem-Text { padding: 10px; line-height: 150px; white-space: nowrap; color: white; } /* CSS for the zoomed-in ListView */ #zoomedInListView { width: 600px; height: 300px; border: solid 2px rgba(0, 0, 0, 0.13); } #semanticZoomDiv { width: 600px; height: 300px; border: solid 2px rgba(0, 0, 0, 0.13); }
运行应用。你会看到两个 ListView 控件:
第一个 ListView 提供放大的视图,而第二个提供缩小的视图。请注意,这两个控件都使用水平布局。我们建议数据的放大视图和缩小视图始终使用相同的布局。
添加 SemanticZoom 控件
在你的标记中,创建 SemanticZoom 控件并将你的 ListView 控件移到其中。
<div id="semanticZoomDiv" data-win-control="WinJS.UI.SemanticZoom">
<!-- The zoomed-in view. -->
<div id="zoomedInListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemDataSource: myData.groupedItemsList.dataSource, itemTemplate: select('#mediumListIconTextTemplate'), groupHeaderTemplate: select('#headerTemplate'), groupDataSource: myData.groupedItemsList.groups.dataSource, selectionMode: 'none', tapBehavior: 'none', swipeBehavior: 'none' }"
></div>
<!--- The zoomed-out view. -->
<div id="zoomedOutListView"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemDataSource: myData.groupedItemsList.groups.dataSource, itemTemplate: select('#semanticZoomTemplate'), selectionMode: 'none', tapBehavior: 'invoke', swipeBehavior: 'none' }"
></div>
</div>
现在,在运行该应用时,你将看到一个 ListView,而且可以在你定义的两个视图之间缩放。
注意 不要在 SemanticZoom 控件的子控件上设置边框。 如果你在 SemanticZoom 及其子控件上设置边框,则 SemanticZoom 边框以及视野范围内的子控件的边框都将可见。在放大/缩小时,子控件的边框会随着内容一起缩放,而且看上去不太好看。仅在 SemanticZoom 控件上设置边框。
使用 SemanticZoom
在两个视图之间缩放:
输入机制 | 缩小 | 放大 |
---|---|---|
触摸 | 扩大 | 收缩,点击 |
键盘 | Ctrl + 减号、Enter | Ctrl + 加号、Enter |
鼠标 | Ctrl + 向后滚动鼠标滚轮 | Ctrl + 向前滚动鼠标滚轮 |
针对自定义控件使用 SemanticZoom
若要针对 ListView 以外的控件使用 SemanticZoom,则必须实现 IZoomableView 接口。有关展示具体做法的示例,请参阅自定义控件的 SemanticZoom 示例。
保持 SemanticZoom 的可响应性
用户可以在 SemanticZoom 的放大视图和缩小视图之间快速顺畅地进行切换,这一点很重要。这表示,SemanticZoom 控件的子控件在加载其数据时不应该让应用等待。将 ListView(或已自定义用于实现 IZoomableView 的 FlipView 版本)与 SemanticZoom 结合使用时,使用模板函数,该函数会在控件在视图中可见但项目不可见的情况下创建占位符。有关在项模板中使用占位符的更多信息,请参阅 FlipView.itemTemplate。如果将自定义控件与 SemanticZoom 结合使用,则当项目可能不可见时实现进度环并使用占位符。
示例
摘要和后续步骤
你已经了解如何创建使用两个 ListView 控件的 SemanticZoom 来创建放大和缩小视图。
现在,可以通过阅读 SemanticZoom 控件指南和清单来了解有关何时以及如何使用 SemanticZoom 的更多信息。