У вас есть данные. Много данных. Вам нужно представлять их так, чтобы пользователи могли без усилий обращаться к ним в вашем приложении. Приложения предоставляют свои данные в виде новостных статей, рецептов, результатов спортивных матчей, финансовых сводок и т. д., — все они выстраиваются на экране в разделах разного размера и пытаются привлечь внимание потребителя. Огромное количество приложений на рынке представляет данные в сетках или списках, и это имеет смысл, так как сетки малого или среднего размера с данными легко воспринимаются человеком; в них можно выполнять поиск и фильтрацию. В любых приложениях — от корпоративных до персональных — сетки являются той основой, которая обеспечивают наглядное представление данных.
В приложениях Windows Store можно настроить эту структуру для представления данных с помощью элемента управления ListView. Если вы новичок в разработке приложений Windows Store, советую прочитать мои статьи «Create Windows Store Apps with HTML5 and JavaScript» за февраль 2013 г. (msdn.microsoft.com/magazine/jj891058) и «Mastering Controls and Settings in Windows Store Apps Built with JavaScript» за июль 2013 г. (msdn.microsoft.com/magazine/dn296546).
Основы элемента управления ListView
ListView, доступный как в HTML, так и в XAML, является лучшим на сегодняшний день элементом управления для представления данных в сетке или в формате списка. В приложениях Windows Library for JavaScript (WinJS) (им уделяется основное внимание в этой статье) элемент управления ListView можно использовать, задав атрибут data-win-control в элементе <div> как «WinJS.UI.ListView»:
<div id="listView" data-win-control= "WinJS.UI.ListView"></div>
Элемент <div>, в котором размещен ListView, не содержит дочерних элементов. Однако в нем есть базовая конфигурационная информация в атрибуте data-win-options. Этот атрибут позволяет задавать любое свойство в ListView, используя декларативный синтаксис в HTML-странице. Чтобы правильно работать с ListView, вам потребуется применить к нему:
- шаблоны групп и элементов в ListView;
- источники данных для групп и элементов в ListView;
- разметку сетки или списка (по умолчанию — сетку).
Вы должны также указать режим выбора элементов в ListView — одиночный или множественный (по умолчанию — множественный). Базовый ListView с разметкой и свойствами selectionMode, установленными в атрибуте data-win-options, выглядит так:
<div id="listView" data-win-control= "WinJS.UI.ListView" data-win-options=
"{ selectionMode: 'single', layout : {type: WinJS.UI.GridLayout} }" ></div>
Хотя предыдущий код определяет ListView, сам по себе этот элемент управления не работает. Ему нужна помощь объекта WinJS.Binding.List. Объект List связывает массивы, заполненные объектами, с HTML-элементами, определенными в шаблонах элементов и групп. То есть объект List определяет отображаемые данные, а шаблон — то, как они показываются.
Создание шаблонов ListView
Настроив <div> для ListView, можно перейти к созданию шаблонов. ListView полагается на HTML-шаблоны в отображении данных, читаемых пользователем. К счастью, шаблоны Grid, Split и Hub (Hub доступен в Windows 8.1) в приложениях Windows Store содержат все, что нужно для представления данных в сетке или в формате списка, в том числе образцы данных, предопределенные элементы управления ListView и предопределенные CSS-классы. Вы можете модифицировать эти шаблоны или создать собственные. Но заметьте: если вы создаете свои шаблоны, то должны придерживаться принципов дизайна современного UI и контурной сетки Windows 8, как описано в Dev Center для приложений Windows Store (bit.ly/IkosnL). При использовании встроенных шаблонов Visual Studio это делается за вас.
ListView требует шаблон элемента (item template), а если вы группируете данные, то и шаблон заголовка. Родительские элементы шаблонов элемента и группы — простые элементы <div> с атрибутом data-win-control, установленным в «WinJS.Binding.Template».
Шаблон заголовка (header template) должен содержать ссылки для каждой группы, что при щелчке пользователь переходил на страницу, где перечисляются элементы, относящиеся к данной группе. Это пример довольно распространенного навигационного шаблона «основной/подробности» (master/detail). На рис. 1 <div> имеется класс headertemplate и содержит элемент <button>, связанный с ключом группы. Когда пользователь касается кнопки или щелкает ее, он переходит на страницу с элементами этой группы.
Рис. 1. Шаблоны заголовка и элемента для ListView
<div class="headertemplate" data-win-control="WinJS.Binding.Template">
<button class="group-header win-type-x-large win-type-interactive"
data-win-bind="groupKey: key"
onclick="Application.navigator.pageControl
.navigateToGroup(event.srcElement.groupKey)"
role="link" tabindex="-1"
type="button">
<span class="group-title win-type-ellipsis" data-win-bind=
"textContent: title"></span>
<span class="group-chevron"></span>
</button>
</div>
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
<div class="item">
<img class="item-image" src="#" data-win-bind=
"src: backgroundImage; alt: title" />
<div class="item-overlay">
<h4 class="item-title" data-win-bind="textContent: title"></h4>
<h6 class="item-subtitle win-type-ellipsis" data-win-bind=
"textContent: subtitle"></h6>
</div>
</div>
</div>
Шаблон элемента на рис. 1 состоит из тегов <div>, в которые заключены изображение и два текстовых поля. Большая часть нынешних данных в современных приложениях имеет графическую форму, поэтому в шаблоне элемента присутствует элемент <img>. Этот элемент заполняется данными изображения, которое представлено простым сплошным серым цветом. На рис. 2 изображен ListView по умолчанию из Grid Layout.
Рис. 2. ListView по умолчанию из шаблона Grid с заголовком и навигационными кнопками, помеченными красным цветом
После кодирования шаблонов элемента и группы можно подключать их к каким-либо данным.
Данные и связывание с данными с помощью элемента управления ListView
JavaScript и JSON идут рука об руку (в конце концов, JSON — это JavaScript Object Notation), поэтому, как только вы получили некие JSON-данные, просто поместите их в массив, и объект Windows.Binding.List преобразует их в источник данных, которым может пользоваться ListView. Иначе говоря, вы не связываете напрямую ListView с массивом или источником данных, а это означает, что объект List действует как посредник между ListView и источником данных. Дело в том, что объект List преобразует данные в формат, понятный ListView, — сам ListView лишь определяет внешний вид и разметку сетки. Объект List также предоставляет методы для поиска, сортировки, добавления и удаления членов нижележащего массива.
Изучив файл \js\data.js вы обнаружите пространство имен Data, а также массивы, образующие примеры данных. В сухом остатке получается, что между двумя массивами образуется связь «основной/подробности» (master/detail). Свойство group каждого объекта в массиве sampleItems (подробности) относится к его группе в массиве sampleGroups (основной), как показано на рис. 3.
Рис. 3. Образцы данных в форме массива в шаблоне проекта Grid
var sampleGroups = [
{ key: "group1", title: "Group Title: 1",
subtitle: "Group Subtitle: 1",
backgroundImage: darkGray, description: groupDescription },
{ key: "group2", title: "Group Title: 2",
subtitle: "Group Subtitle: 2",
backgroundImage: lightGray, description: groupDescription },
{ key: "group3", title: "Group Title: 3",
subtitle: "Group Subtitle: 3",
backgroundImage: mediumGray, description: groupDescription }
];
var sampleItems = [
{ group: sampleGroups[0], title: "Item Title: 1",
subtitle: "Item Subtitle: 1",
description: itemDescription,
content: itemContent, backgroundImage: lightGray },
{ group: sampleGroups[0], title: "Item Title: 2",
subtitle: "Item Subtitle: 2",
description: itemDescription,
content: itemContent, backgroundImage: darkGray },
{ group: sampleGroups[0], title: "Item Title: 3", subtitle:
"Item Subtitle: 3",
description: itemDescription,
content: itemContent, backgroundImage: mediumGray },
{ group: sampleGroups[1], title: "Item Title: 1", subtitle:
"Item Subtitle: 1", description: itemDescription,
content: itemContent, backgroundImage: darkGray },
{ group: sampleGroups[2], title: "Item Title: 2", subtitle:
"Item Subtitle: 2", description: itemDescription,
content: itemContent, backgroundImage: mediumGray },
];
Конечно, вы замените образцы данных своими, создав собственные массивы, обратившись к JSON- или XML-данным или, возможно, вызвав некий веб-сервис. Вы не обязаны использовать пространство имен Data и вместо него можете определить свое пространство.
Почти в самом начале файла data.js есть такая строка кода:
var list = new WinJS.Binding.List();
Эта переменная list является контейнером для массива. Вы можете добавить массив в List, передав его методу конструктора List или используя метод push:
generateSampleData().forEach(function (item) {
list.push(item);
});
Это приведет к заполнению списка данными массива, и теперь вы готовы связать список и ListView. Если вы используете код шаблона по умолчанию, то должны выполнять это связывание при первой загрузке приложения, в функции _initializeLayout файла \js\default.js:
listView.itemDataSource = Data.items.dataSource;
listView.groupDataSource = Data.groups.dataSource;
Разумеется, в зависимости от размера ваших данных время загрузки может варьироваться, поэтому вам, возможно, потребуется модифицировать процесс загрузки. Подходите к загрузке данных в память с трезвым расчетом и не забывайте о важности быстродействия для пользователей.
Заметьте, что источники данных для элементов и групп присваиваются Data.items.dataSource и Data.groups.dataSource соответственно. Члены items и groups пространства имен Data ссылаются обратно на функции, которые создали массив, содержащий данные (т. е. groupedItems). Объявление пространства имен Data в файле \js\data.js отражает эту нотацию и показывает другие открытые члены в этом пространстве имен для работы с данными:
WinJS.Namespace.define("Data", {
items: groupedItems,
groups: groupedItems.groups,
getItemReference: getItemReference,
getItemsFromGroup: getItemsFromGroup,
resolveGroupReference: resolveGroupReference,
resolveItemReference: resolveItemReference
});
Члены items и groups пространства имен Data указывают на объект groupedItems, который конструировал данные. Все, что вы до сих пор видели в пространстве имен Data, включено в шаблоны проектов Visual Studio. Если вы предпочтете начать с пустым проектом, вам понадобится самостоятельно формировать данные по образцу, создавая аналогичные методы доступа к данным вместо того, чтобы полагаться на члены пространства имен Data.
К этому моменту ListView заполнен данными и привязки настроены. Вы можете связывать свойства объектов в источнике данных с HTML-элементами, используя атрибут data-win-bind:
<h4 class="item-title" data-win-bind="textContent: title"></h4>
Эта строка кода связывает свойство title с элементом <h4> как часть его текста. На рис. 1 и 2 вы найдете больше примеров работы с атрибутом data-win-bind.
Теперь, когда у вас есть ListView и доступ к данным готов, пора переходить к оформлению ListView.
Стилизация элемента управления ListView
Внешний вид целиком зависит от стилей. Библиотеки WinJS содержат полный набор CSS-правил с предопределенными стилями, которые вы можете переопределять для изменения внешнего вида ListView в самых широких пределах. Если вы не знакомы со стилизацией WinJS-элементов управления, см. мою статью «Build a Responsive and Modern UI with CSS for WinJS Apps» в номере за октябрь 2013 г. (msdn.microsoft.com/magazine/dn451447). Вы можете применять стили ко всему ListView, перезаписывая CSS-класс .win-listview. Наряду со стилизацией ListView вы можете заменять составные части ListView с помощью следующих селекторов классов:
- .win-viewport — стилизует окно вывода ListView. В этом окне располагаются полосы прокрутки;
- .win-surface — стилизует область прокрутки ListView. Эта область смещается при прокрутке пользователем.
Есть два способа стилизации элементов в ListView. Вы можете применять стили к шаблону элемента через класс .win-item или переопределять класс .win-container. Учтите, что каждый элемент в ListView состоит из нескольких HTML-элементов (взгляните на рис. 1, чтобы посмотреть эти элементы). Как видно на рис. 1, элементы <div>, которые образуют шаблон элемента, содержат классы .item, .item-image, .item-overlay, .item-title и .item-subtitle. Ни один из них не определен в системных таблицах стилей (т. е. ui-light и ui-dark), поскольку эта задача возлагается на вас.
Вы должны знать о множестве подвохов, связанных со стилизацией, особенно при применении полей и дополнении пробелами в элементе управления ListView. Все детали стилизации ListView см. в Dev Center для приложений Windows Store (bit.ly/HopfUg). Не забудьте создать стили для всех состояний отображения, которые могут понадобиться вашему приложению.
В Windows 8.1 произошли некоторые изменения в стилях для ListView, касающиеся специфики селектора «дочерний/потомок» (child/descendant selector). Это вызвано тем, что во внутренней древовидной структуре страницы появился новый узел, поэтому вы должны обновить свои CSS-селекторы для включения .win-itembox, например .win-container | .win-itembox | .win-item.
Реакция ListView на изменения представления
Реагирование на новые представления Snap и Filled в Windows 8 важно для прохождения процесса сертификации Windows Store. Представление Snap наряду с Full и Filled — это то, как пользователи могут упорядочивать несколько приложений Windows Store на экране. В Windows 8 пользователи могут изменять размеры максимум двух открытых окон приложений: одно — в представлении Filled и одно — в представлении Snap. В Windows 8.1 максимальное количество окон увеличено до четырех, поэтому появилось больше вариантов отображения приложений. Эти представления называются Tall или Narrow в Windows 8.1, и они слегка отличаются от представлений Snap и Filled в Windows 8.
Это означает, что вы должны программировать элемент управления ListView так, чтобы он изменял свой формат при изменении режима отображения приложения. Этот процесс называется адаптивным дизайном (responsive design), и вы можете реализовать его с помощью media-запросов CSS. Введение в media-запросы CSS см. в моей статье в блоге «Create mobile site layouts with CSS Media Queries» (bit.ly/1c39mDx).
Media-запросы определяют форму ListView так, чтобы она подходила под разные представления. При переключении в представление Tall элемент ListView нужно преобразовать в список:
listView.layout = new ui.ListLayout();
Впоследствии, когда пользователь вернется к исходному представлению, вы должны вновь сделать ListView сеткой:
listView.layout = new ui.GridLayout({ groupHeaderPosition: "top" });
Если вы хотите изменять стили элементов в ListView при изменении экрана, добавьте CSS в следующий media-запрос в файле \css\default.css:
@media screen and (-ms-view-state: snapped) {...}
Вам не нужен media-запрос для представлений Full и Filled, так как в них используются таблицы стилей по умолчанию. Однако вы можете использовать различные media-запросы для разнообразных размеров экрана, если это вам нужно.
ListView и контекстное масштабирование
Римейк Windows в версии 8 повлек за собой новые способы визуализации, навигации и поиска данных. То есть теперь вы должны иначе подходить к поиску. Вместо того чтобы пользователи вводили фразы в поля поиска и просеивали длинные списки результатов, теперь можно применять контекстное масштабирование (semantic zoom) для концентрации данных в удобоваримых разделах.
Контекстное масштабирование позволяет вести поиск с помощью жеста щипка (или Ctrl + колесо мыши) для панорамирования или уменьшения масштаба и наблюдения данных в агрегатном формате. Например, так ведет себя страница Windows Start, показывая пользователям все доступные приложения в уменьшенном масштабе. Применять контекстное масштабирование в приложении несложно, поскольку для WinJS это просто элемент управления:
<div data-win-control="WinJS.UI.SemanticZoom">
<!-- Сюда помещается элемент управления, который обеспечивает представление с увеличением масштаба -->
<!-- Сюда помещается элемент управления, который обеспечивает представление с уменьшением масштаба -->
</div>
Элемент управления SemanticZoom — это просто оболочка для одного-двух ListView или, возможно, HTML-элемента управления Repeater, который является новинкой в Windows 8.1.
Всякая всячина о ListView
Не используйте ListView как универсальный элемент управления для разметки. Для таких целей применяйте рамочную модель (box model) в CSS. В Windows 8.1 вы должны подумать, что для вас лучше — ListView или Repeater. Элемент Repeater предпочтительнее, если вам не требуется слишком много функциональности от элемента управления и нужно лишь многократно повторять один и тот же HTML-дизайн. На момент написания этой статьи Windows 8.1 находилась в состоянии предварительной версии, поэтому в ListView могут быть внесены и какие-то другие изменения — равно как и в API компонентов приложений Windows Store. Подробнее об изменениях в Windows 8.1 API см. документацию в Dev Center по ссылке bit.ly/1dYTylx.