Поделиться через


Как настраивать данные шаблона Visual Studio (HTML)

[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. При разработке приложений для Windows 10 см. раздел последняя документация]

В шаблонах "Сводная таблица/концентратор", "Приложение-концентратор", "Сводная таблица", "Приложение таблицы" и "Приложение с разделением" код, который получает данные, необходимые для приложения, находится в файле data.js. Этот файл представляет собой источник демонстрационных данных для приложения. Файл data.js содержит статические данные, которые обычно следует заменять динамическими данными. Например, если приложение посылает один запрос xhr на получение данных RSS или JSON, следует включить этот код в data.js. Включив этот код, вы сможете с легкостью использовать собственные данные, не меняя модель данных, представленную в шаблонах.

Совет  Шаблоны "Приложение-концентратор/сводное приложение", "Сводное приложение" и "Приложение-концентратор" также получают статические данные из RESJSON-файлов, поддерживающих глобализацию. Подробнее: Пример привязки данных к пользовательскому интерфейсу в шаблонах "Приложение-концентратор/сводное приложение", "Сводное приложение" и "Приложение-концентратор".

 

Добавляя собственные данные в приложение, учитывайте следующие особенности.

  • Группы и элементы неразрывно связаны. С точки зрения приложения данные элементов организованы в группы. Вы можете разорвать связь между группами и элементами в собственной реализации, но тогда для правильной работы необходимо будет изменить код. В этом разделе описывается использование групп в модели данных шаблона.
  • При добавлении дополнительных данных для приложения в файл data.js убедитесь, что имена свойств, присущие вашим данным, соответствуют именам свойств, применяемым в шаблоне. Вы можете изменить имена, заданные шаблоном, но для этого потребуются более серьезные изменения кода. В этом разделе описан пример подобных изменений.

Элементы и группы

Данные шаблонов хранятся в WinJS.Binding.List. Ниже приведен фрагмент кода, демонстрирующий объявление списка в файле data.js.

var list = new WinJS.Binding.List();

Массив данных элементов (в этом примере — sampleItems) передается в WinJS.Binding.List с помощью функции push, как показано здесь:

generateSampleData.forEach(function (item) {
    list.push(item);
});

WinJS.Binding.List содержит внутреннюю логику для обработки группирования данных. Массив sampleItems имеет свойство group, определяющее группу, к которой принадлежит элемент (в нашем примере — sampleGroups). Пример массива данных элемента в функции generateSampleData:

function generateSampleData() {
    // . . .
    var sampleGroups = [
        { key: "group1", title: "Group Title: 1", // . . .
        // . . .
    ];

    var sampleItems = [
        { group: sampleGroups[0], title: "Item Title: 1", // . . .
        // . . .
    ];

    return sampleItems;
}

При изменении приложения в соответствии с дополнительными данными вам может потребоваться использовать аналогичный способ для группирования данных. Для небольших наборов данных рекомендуется использовать WinJS.Binding.List для ListView. WinJS.Binding.List можно использовать также и если группирование элементов не требуется, но тогда вам придется изменить код шаблона во всех фрагментах, в которых могут оказаться сгруппированные данные.

Совет  WinJS.Binding.List является источником синхронных данных, использующим массив JavaScript. Для очень больших наборов данных, включающих несколько тысяч элементов, возможно, потребуется источник асинхронных данных. Подробнее см. в разделе Использование ListView.

 

Функция createGrouped из WinJS.Binding.List указывает, как группировать элементы с помощью ключа группировки и значения номенклатурной группы. Функция вызывается в data.js. key и group — названия свойств, используемых в массивах примеров данных.

var groupedItems = list.createGrouped(
    function groupKeySelector(item) { return item.group.key; },
    function groupDataSelector(item) { return item.group; }
);

Когда приложению из шаблона требуется список элементов, оно вызывает метод getItemsFromGroup, который возвращает список WinJS.Binding.List, содержащий только принадлежащие указанной группе элементы.

function getItemsFromGroup(group) {
    return list.createFiltered(function (item) {
        return item.group.key === group.key;
    });
}

Совет  Такие функции, как getItemsFromGroup, которые вызывают createFiltered, создают новую проекцию для WinJS.Binding.List, и вам может понадобиться ликвидировать возвращенный объект, если вы уходите со страницы. Чтобы ликвидировать объект, вызовите метод WinJS.Binding.List.dispose.

 

Функция define из библиотеки Windows для JavaScript предоставляет данные для использования в приложении, указывая пространство имен Data и набор функций для общих членов.

WinJS.Namespace.define("Data", {
    items: groupedItems,
    groups: groupedItems.groups,
    getItemReference: getItemReference,
    getItemsFromGroup: getItemsFromGroup,
    resolveGroupReference: resolveGroupReference,
    resolveItemReference: resolveItemReference
});

Если вы хотите определить для разных страниц приложения разные источники данных или модели данных, то вам придется заменить все вызовы этих членов в коде JavaScript.

Привязка данных групп и элементов к пользовательскому интерфейсу

В следующем фрагменте кода показана разметка для элемента управления ListView. Источник данных для ListView указан в свойстве itemDataSource, как показано здесь. Этот пример из split.html в шаблоне "Приложение с разделением".


<div class="itemlist win-selectionstylefilled" aria-label="List of this group's items" data-win-control="WinJS.UI.ListView" data-win-options="{
    layout: {type: WinJS.UI.ListLayout},
    currentItem: {type: WinJS.UI.ObjectType.item, index: 0, hasFocus: true},
    selectionMode: 'single',
    swipeBehavior: 'none',
    tapBehavior: 'toggleSelect',
    itemDataSource: select('.pagecontrol').winControl.itemDataSource,
    itemTemplate: select('.itemtemplate'),
    onselectionchanged: select('.pagecontrol').winControl.selectionChanged
    }">
</div>

В предшествующем коде свойство itemDataSource, связанное со страницей, назначается свойству itemDataSource элемента управления ListView.

Данные в шаблонах обычно связаны с пользовательским интерфейсом с помощью функции init или функции ready, которая определена в JS-файле, связанном с каждой HTML-страницей. В функции init для split.html содержится следующий фрагмент кода. В данном примере приложение получает ссылку на группу, а затем вызывает функцию getItemsFromGroup, реализованную в data.js. Как упоминалось ранее, функция getItemsFromGroup возвращает список WinJS.Binding.List, содержащий только элементы указанной группы.

this._group = Data.resolveGroupReference(options.groupKey);
this._items = Data.getItemsFromGroup(this._group);

Затем мы связываем список, возвращенный getItemsFromGroup свойству страницы itemDataSource, которое связывает данные с ListView, после чего указываем обработчик для выбора элемента (_selectionChanged).


this.itemDataSource = this._items.dataSource;
this.selectionChanged = ui.eventHandler(this._selectionChanged.bind(this));

Как показано в примере, для отображения каждого элемента в ListView приложение связывает шаблон с ListView. Этот код появляется в разметке для элемента управления ListView. Код использует свойство itemTemplate для указания элемента DIV с именем класса itemtemplate.

itemTemplate: select('.itemtemplate')

Шаблоны WinJS на основе WinJS.Binding.Template используются для форматирования и отображения множества экземпляров данных. Наиболее часто в шаблонах приложений "Приложение с разделением" и "Приложение таблицы" используется шаблон для отображения элементов в ListView. Как и любой объект шаблона WinJS, вы можете объявить его, добавив атрибут data-win-control и присвоив его шаблону WinJS.Binding.Template. Ниже приведен HTML-код для itemtemplate в split.html:

<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-info">
            <h3 class="item-title win-type-ellipsis" 
                data-win-bind="textContent: title"></h3>
            <h6 class="item-subtitle win-type-ellipsis"
                data-win-bind="textContent: author"></h6>
        </div>
    </div>
</div>

Шаблон itemtemplate используется для случайных элементов ListView. Элементы ListView могут быть как группами, так и отдельными элементами данных в зависимости от контекста. Например, в файле items.html элементы ListView являются группами.

Важно  Шаблоны, создаваемые с помощью WinJS.Binding.Template, не относятся к проекту Visual Studio и шаблонам "Разделенное приложение" и "Приложение таблицы".

 

Шаблоны проектов предполагают наличие у данных определенных свойств, и эти свойства явным образом указаны в HTML-коде. В предыдущем фрагменте HTML-кода для itemtemplate такими свойствами являются title, subtitle. Если в пользовательских данных приложения имена этих свойств не используются, поступите так:

  • Сопоставьте свои данные с именами этих свойств (обычно это нужно сделать в файле data.js). Либо:
  • Исправьте в коде HTML и JS шаблона все ссылки на эти свойства таким образом, чтобы они соответствовали именам свойств, используемых в ваших данных. К свойствам, которые используются в шаблонах, относятся:
    • title, subtitle, description и backgroundImage (свойства групп и элементов)
    • group и content (свойства элементов)
    • key (свойство группы)

По аналогии с шаблоном WinJS в шаблоне "Приложение таблицы" также используется headerTemplate на некоторых HTML-страницах.

Пример привязки данных к пользовательскому интерфейсу в шаблонах "Сводная таблица/концентратор", "Приложение-концентратор" и "Сводная таблица"

В Visual Studio шаблоны проекта "Сводная таблица-концентратор", "Приложение-концентратор" и "Сводная таблица" показывают, как реализовать два различных источника данных:

  • Глобализированные статические данные, хранящиеся в файлах ресурсов с расширением RESJSON. Эти данные используются в некоторых разделах приложения (элементы управления PivotItem или HubSection).
  • Пример данных в файле data.js, который представляет модель данных. Этот файл такой же, как в шаблонах "Приложение таблицы" и "Приложение с разделением". Этот пример данных используется в элементе управления ListView в одном из разделов приложения.

Декларативные функции в HTML используются для первоначального получения данных примера, а модель данных по умолчанию является синхронной. Чтобы настроить шаблоны для использования динамических данных во всех разделах, необходимо внести несколько изменений в файлы hub.html, hub.js и другие. В следующих примерах приложений показано, как настроить шаблоны "Сводная таблица-концентратор" и "Приложение-концентратор" для поддержки асинхронных данных:

Так как глобализированные данные в RESJSON-файле легко заменить, в примерах приложений этот файл ресурсов остается без изменений. В примерах приложений данные для элементов <img> и элемента управления ListView, присутствующих в разделах шаблона "Сводная таблица-концентратор", возвращаются асинхронно.

Подробнее о предоставлении глобализированных данных в RESJSON-файлах: Краткое руководство: перевод ресурсов пользовательского интерфейса

Для поддержки привязки асинхронных данных к элементу управления ListView шаблона "Сводная таблица-концентратор" замените глобальные переменные, вызывающие модель данных, в файле hub.js.

var section3Group = Data.resolveGroupReference("group4");
var section3Items = Data.getItemsFromGroup(section3Group);

с помощью этих объявлений переменных:


var section3Group = "group2";
var section3Items;

В файле hub.js также потребуется изменить реализацию декларативных функций. В реализации шаблона по умолчанию эти функции зависят от доступных данных (например, вызов section3Items.dataSource). Замените этот код:

section3DataSource: section3Items.dataSource,

section3HeaderNavigate: util.markSupportedForProcessing(function (args) {
    nav.navigate("/pages/section/section.html", { title: args.detail.section.header, 
        groupKey: section3Group.key });
}),

section3ItemNavigate: util.markSupportedForProcessing(function (args) {
    var item = Data.getItemReference(section3Items.getAt(args.detail.itemIndex));
    nav.navigate("/pages/item/item.html", { item: item });
}),

на


section3DataSource: null,

section3HeaderNavigate: util.markSupportedForProcessing(function (args) {
    nav.navigate("/pages/section/section.html", { title: args.detail.section.header,
        groupKey: section3Group });
}),

section3ItemNavigate: util.markSupportedForProcessing(function (args) {
    var itemSet = section3Items;
    var itemObj = itemSet.getAt(args.detail.itemIndex);
    var item = [itemObj.group.key, itemObj.title, itemObj.backgroundImage];

    nav.navigate("/pages/item/item.html", { item: item });
}),

Этот код задает для функции section3DataSource значение NULL, чтобы избежать привязки данных до их доступности. Источник данных мы зададим дальше в функции привязки данных (_bindData или bindListView, в зависимости от примера приложения).

Функция привязки данных вызывается, когда данные становятся доступны. Для этого мы добавим прослушиватель для события dataReady модели данных, определенного в примере приложения в файле data.js.


this._observer = Data.getObservable();
this._observer.addEventListener('dataReady', this.onDataCompleted.bind(this));

Приложение вызывает функцию привязки данных из обработчика событий onDataCompleted (который здесь не приводится). Далее показан код функции _bindData в примере шаблона "Приложение-концентратор". В этом фрагменте кода мы устанавливаем свойство itemDataSource элемента ListView.


_bindData: function (context, grp1Items, grp2Items) {

    var self = context;

    // . . .

    self._items = grp2Items;
    section3Items = self._items;
    self._section3lv.itemDataSource = self._items.dataSource;

    // . . .   

},

Если для перехода на страницу используется кнопка "Назад", то функция привязки данных вызывается непосредственно из функции инициализации страницы, поскольку нет необходимости ожидать новые данные.

Совет  В коде шаблона "Приложение-концентратор" приложение вызывает функцию _hubReady из обработчика событий loadingstatechanged элемента управления "Главный раздел", чтобы запросить в модели DOM элемент ListView (хранящийся в разделе _section3lv). Это событие активируется только после окончания загрузки страницы-концентратора. Использование этого обработчика событий позволяет запросить модель DOM, чтобы получить вложенный элемент DIV, связанный с элементом ListView.

 

Полный код для использования асинхронных данных в шаблонах "Приложение-концентратор/сводное приложение" и "Приложение-концентратор" см. в примерах JSON Web reader that uses the Hub/Pivot template и JSON Web reader that uses the Hub template. Помимо описанной здесь настройки, мы внесли в пример приложения следующие изменения:

  • В модель данных (data.js) добавлен код для получения данных при помощи запроса xhr, а также для анализа данных JSON (из Flickr).
  • В модель данных добавлен код для обработки множественных запросов данных и для активации события dataReady при возвращении данных.
  • В пользовательский интерфейс добавлено окно ввода для запроса новых данных.
  • Добавлен индикатор выполнения для отображения состояния запроса данных.
  • К полю ввода и индикатору выполнения добавлены элементы стиля CSS.
  • Добавлены функции для инициализации страницы после полной загрузки элемента управления "Главный раздел" (такие как _hubReady и _hubReadyPhone).
  • Элементы <img> в шаблоне "Сводная таблица/концентратор" или "Приложение-концентратор" изменены для поддержки событий щелчка (изменяемые файлы зависят от шаблона).
  • Изменены файлы для привязки асинхронных данных к элементам <img> в шаблоне "Сводная таблица/концентратор" или "Приложение-концентратор" (изменяемые файлы зависят от шаблона).
  • Файл hub.js изменен для поддержки перехода к изображениям из элементов <img> главного раздела (изменяемые файлы зависят от шаблона).
  • Для поддержки просмотра одиночных изображений изменены файлы item.html и item.js.

Пример привязки данных к пользовательскому интерфейсу (для шаблонов "Приложение таблицы" и "Приложение с разделением")

В этом разделе показано, как реализовать собственный источник данных на основе шаблонов проектов "Приложение таблицы" и "Приложение с разделением". В образце кода используется запрос xhr для создания данных RSS.

Важно  Реализацию асинхронных данных в шаблоне "Приложение-концентратор" см. в разделе Привязка данных к пользовательскому интерфейсу в шаблоне "Приложение-концентратор".

 

Обновление файла data.js

  1. Создайте новый проект в Visual Studio. Используйте шаблон проекта "Приложение с разделением" или "Приложение таблицы".

  2. В начале файла data.js добавьте следующие переменные после оператора use strict:

    var lightGray = "data:image/png;base64,
        iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
    var mediumGray = "data:image/png;base64,
        iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";
    
  3. В коде файла data.js удалите функцию generateSampleData, которая содержит массивы sampleGroups и sampleItems.

    Мы заменим их данными RSS. Мы не будем использовать большинство переменных-заполнителей, например groupDescription, но для правильной работы нового кода мы повторно используем изображения-заполнители lightGray и mediumGray.

  4. Там, где вы удалили generateSampleData, добавьте следующий код в data.js:

    
    function getFeeds() {
        // Create an object for each feed.
        blogs = [
            {
                key: "blog1", url: 
           'https://windowsteamblog.com/windows/b/developers/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "blog2", url: 
           'https://windowsteamblog.com/windows/b/windowsexperience/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            }]
        // Get the content for each feed in the blog's array.
        blogs.forEach(function (feed) {
            feed.dataPromise = feed.acquireSyndication(feed.url);
            dataPromises.push(feed.dataPromise);
        });
    
        // Return when all asynchronous operations are complete
        return WinJS.Promise.join(dataPromises).then(function () {
            return blogs;
        });
    
    };
    
    function acquireSyndication(url) {
        return WinJS.xhr(
        {
            url: url,
            headers: { "If-Modified-Since": "Mon, 27 Mar 1972 00:00:00 GMT" }               
        });
    }
    
    function getBlogPosts() {
        getFeeds().then(function () {
            // Process each blog.
            blogs.forEach(function (feed) {
                feed.dataPromise.then(function (articlesResponse) {
                    var articleSyndication = articlesResponse.responseXML;
    
                    // Get the blog title and last updated date.
                    if (articleSyndication) {
                        // Get the blog title and last updated date.
                        feed.title = articleSyndication.querySelector(
                            "feed > title").textContent;
                        var ds = articleSyndication.querySelector(
                            "feed > updated").textContent;
                        var date = ds.substring(5, 7) + "-" +
                            ds.substring(8, 10) + "-" + ds.substring(0, 4);
                        feed.updated = "Last updated " + date;
                        // Process the blog posts.
                        getItemsFromXml(articleSyndication, blogPosts, feed);
                    }
                    else {
                        // There was an error loading the blog. 
                        feed.title = "Error loading blog";
                        feed.updated = "Error";
                        blogPosts.push({
                            group: feed,
                            key: "Error loading blog",
                            title: feed.url,
                            author: "Unknown",
                            month: "?",
                            day: "?",
                            year: "?",
                            content: "Unable to load the blog at " + feed.url
                        });
                    }
                });
            });
        });
    
        return blogPosts;
    }
    
    function getItemsFromXml(articleSyndication, blogPosts, feed) {
        var posts = articleSyndication.querySelectorAll("entry");
        // Process each blog post.
        for (var postIndex = 0; postIndex < posts.length; postIndex++) {
            var post = posts[postIndex];
            // Get the title, author, and date published.
            var postTitle = post.querySelector("title").textContent;
            var postAuthor = post.querySelector("author > name").textContent;
            var pds = post.querySelector("published").textContent;
            var postDate = pds.substring(5, 7) + "-" + pds.substring(8, 10)
                + "-" + pds.substring(0, 4);
            // Process the content so that it displays nicely.
            var staticContent = toStaticHTML(post.querySelector(
                "content").textContent);
            // Store the post info we care about in the array.
            blogPosts.push({
                group: feed, key: feed.title, title: postTitle, 
                author: postAuthor, pubDate: postDate, 
                backgroundImage: mediumGray, content: staticContent
            });
        }
    }
    
  5. В файле data.js замените код

    var list = new WinJS.Binding.List();
    var groupedItems = list.createGrouped(
        function groupKeySelector(item) { return item.group.key; },
        function groupDataSelector(item) { return item.group; }
    );
    
    // TODO: Replace the data with your real data.
    // You can add data from asynchronous sources whenever it becomes available.
    generateSampleData.forEach(function (item) {
        list.push(item);
    });
    

    на

    var dataPromises = [];
    var blogs;
    
    var blogPosts = new WinJS.Binding.List();
    
    var list = getBlogPosts();
    var groupedItems = list.createGrouped(
        function groupKeySelector(item) { return item.group.key; },
        function groupDataSelector(item) { return item.group; }
    );
    

    Мы повторно используем код в createGrouped, определяющий группирование: функции—groupKeySelector и groupDataSelector.

    Поскольку мы изменили имена некоторых свойств, заданные в шаблонах, нужно обновить HTML-страницы. То есть для каждого свойства subtitle, ссылающегося на элемент, а не на группу, нужно заменить subtitle на author. А для любого свойства description, ссылающегося на элемент, мы должны заменить description на pubDate.

    Чтобы реализовать эти изменения в пользовательском интерфейсе, см. один из следующих разделов:

    • Привязка образца данных к пользовательскому интерфейсу в шаблоне "Разделенное приложение"
    • Привязка образца данных к пользовательскому интерфейсу в шаблоне "Приложение таблицы"

Привязка образца данных к пользовательскому интерфейсу в шаблоне "Разделенное приложение"

  1. Чтобы использовать пример кода из шаблона Split, откройте split.html.

  2. В файле split.html нужно изменить несколько строк в элементе DIV с именем класса itemtemplate. Измените строку

    
    <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
    

    на

    <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: author"></h6>
    
  3. В файле split.html также нужно обновить информацию заголовка в разделе статьи (articlesection). Измените строку

    <h4 class="article-subtitle" data-win-bind="textContent: subtitle"></h4>
    

    на

    <h4 class="article-subtitle" data-win-bind="textContent: author"></h4>
    
  4. Откройте items.html.

    Элемент шаблона WinJS, определенный в HTML-коде, содержит случайные элементы ListView. На странице items.html шаблон обычно отображает группы (блоги). Единственное свойство группы, которое нужно здесь изменить, это subtitle.

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: subtitle"></h6>
    
  5. Измените свойство subtitle на updated, как показано здесь:

    <h6 class="item-subtitle win-type-ellipsis"
        data-win-bind="textContent: updated"></h6>
    
  6. Сохраните проект и нажмите клавишу F5, чтобы перейти в режим отладки приложения.

    Вы сразу увидите заголовок страницы, но данные веб-канала загрузятся с небольшой задержкой. Когда все условия будут выполнены, вы увидите на домашней странице все блоги. Выберите один из блогов и просмотрите его записи в режиме "основной/подробности".

Привязка образца данных к пользовательскому интерфейсу в шаблоне "Приложение таблицы"

Перед выполнением следующих действий обновите файл проекта data.js, как описано в разделе с примером привязки данных к пользовательскому интерфейсу.

  1. Чтобы использовать пример кода RSS в шаблоне "Приложение таблицы", откройте groupDetail.html.

    На этой странице отображается одна группа (блог) и ее отдельные элементы (записи блога).

  2. В файле groupDetail.html нужно изменить несколько строк в элементе DIV с именем класса item-info. Измените строки:

    
    <h6 class="item-subtitle win-type-ellipsis"
        data-win-bind="textContent: subtitle"></h6>
    <h4 class="item-description" 
        data-win-bind="textContent: description"></h4>
    

    на

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: author"></h6>
    <h4 class="item-description" 
        data-win-bind="textContent: pubDate"></h4>
    

    Шаблон заголовка в файле groupDetail.html содержит информацию о группах, а не об отдельных элементах. Следовательно, свойство subtitle изменять не требуется. Ниже приведен шаблон заголовка:

    
    <div class="headertemplate" data-win-control="WinJS.Binding.Template">
        <h2 class="group-subtitle" data-win-bind="textContent: subtitle"></h2>
        <img class="group-image" src="#" 
            data-win-bind="src: backgroundImage; alt: title" />
        <h4 class="group-description" data-win-bind="innerHTML: description"></h4>
    </div>
    
  3. Но у нас нет свойства description для каждой группы (оно относится к элементам), поэтому в предыдущем фрагменте кода нужно изменить это свойство на updated, как показано здесь.

    <h4 class="group-description" data-win-bind="innerHTML: updated"></h4>
    
  4. Откройте файл groupedItems.html, содержащий все группы и их отдельные элементы (записи блога).

  5. Универсальный шаблон элементов WinJS на этой странице отображает отдельные элементы (записи блога), поэтому нужно обновить свойство subtitle. Измените фрагмент

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: subtitle"></h6>
    

    на

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: author"></h6>
    
  6. Сохраните проект и нажмите клавишу F5, чтобы перейти в режим отладки приложения.

    Вы сразу увидите заголовок страницы, но данные веб-канала загрузятся с небольшой задержкой. Когда данные загрузятся, вы увидите элементы во всех блогах на домашней странице. Щелкните заголовок группы для просмотра ее страницы, либо элемент — для просмотра конкретной записи блога.

Список кода для data.js

Вот полный код для data.js. Тот же файл data.js используется для показанных ранее примеров шаблона "Приложение таблицы" и шаблона "Приложение с разделением". Файл data.js для шаблона "Приложение-концентратор/сводное приложение" см. в примере JSON Web reader that uses the Hub/Pivot template. Файл data.js для шаблона "Приложение-концентратор" см. в примере JSON Web reader that uses the Hub templates.


(function () {
    "use strict";

    
    var lightGray = "data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
    var mediumGray = "data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";


    var dataPromises = [];
    var blogs;

    var blogPosts = new WinJS.Binding.List();

    var list = getBlogPosts();
    var groupedItems = list.createGrouped(
        function groupKeySelector(item) { return item.group.key; },
        function groupDataSelector(item) { return item.group; }
    );

    WinJS.Namespace.define("Data", {
        items: groupedItems,
        groups: groupedItems.groups,
        getItemReference: getItemReference,
        getItemsFromGroup: getItemsFromGroup,
        resolveGroupReference: resolveGroupReference,
        resolveItemReference: resolveItemReference
    });

    // Get a reference for an item, using the group key and item title as a
    // unique reference to the item that can be easily serialized.
    function getItemReference(item) {
        return [item.group.key, item.title];
    }

    // This function returns a WinJS.Binding.List containing only the items
    // that belong to the provided group.
    function getItemsFromGroup(group) {
        return list.createFiltered(function (item) { return item.group.key === group.key; });
    }

    // Get the unique group corresponding to the provided group key.
    function resolveGroupReference(key) {
        return groupedItems.groups.getItemFromKey(key).data;
    }

    // Get a unique item from the provided string array, which should contain a
    // group key and an item title.
    function resolveItemReference(reference) {
        for (var i = 0; i < groupedItems.length; i++) {
            var item = groupedItems.getAt(i);
            if (item.group.key === reference[0] && item.title === reference[1]) {
                return item;
            }
        }
    }



    function getFeeds() {
        // Create an object for each feed.
        blogs = [
            {
                key: "blog1", url:
           'https://windowsteamblog.com/windows/b/developers/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "blog2", url:
           'https://windowsteamblog.com/windows/b/windowsexperience/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            }]
        // Get the content for each feed in the blog's array.
        blogs.forEach(function (feed) {
            feed.dataPromise = feed.acquireSyndication(feed.url);
            dataPromises.push(feed.dataPromise);
        });

        // Return when all asynchronous operations are complete
        return WinJS.Promise.join(dataPromises).then(function () {
            return blogs;
        });

    };

    function acquireSyndication(url) {
        return WinJS.xhr({
            url: url,
            headers: { "If-Modified-Since": "Mon, 27 Mar 1972 00:00:00 GMT" }
        });
    }

    function getBlogPosts() {
        getFeeds().then(function () {
            // Process each blog.
            blogs.forEach(function (feed) {
                feed.dataPromise.then(function (articlesResponse) {
                    var articleSyndication = articlesResponse.responseXML;

                    if (articleSyndication) {
                        // Get the blog title and last updated date.
                        feed.title = articleSyndication.querySelector(
                            "feed > title").textContent;
                        var ds = articleSyndication.querySelector(
                            "feed > updated").textContent;
                        var date = ds.substring(5, 7) + "-" +
                            ds.substring(8, 10) + "-" + ds.substring(0, 4);
                        feed.updated = "Last updated " + date;
                        // Process the blog posts.
                        getItemsFromXml(articleSyndication, blogPosts, feed);
                    }
                    else {
                        // There was an error loading the blog. 
                        feed.title = "Error loading blog";
                        feed.updated = "Error";
                        blogPosts.push({
                            group: feed,
                            key: "Error loading blog",
                            title: feed.url,
                            author: "Unknown",
                            month: "?",
                            day: "?",
                            year: "?",
                            content: "Unable to load the blog at " + feed.url
                        });
                    }
                });
            });
        });

        return blogPosts;
    }

    function getItemsFromXml(articleSyndication, blogPosts, feed) {
        var posts = articleSyndication.querySelectorAll("entry");
        // Process each blog post.
        for (var postIndex = 0; postIndex < posts.length; postIndex++) {
            var post = posts[postIndex];
            // Get the title, author, and date published.
            var postTitle = post.querySelector("title").textContent;
            var postAuthor = post.querySelector("author > name").textContent;
            var pds = post.querySelector("published").textContent;
            var postDate = pds.substring(5, 7) + "-" + pds.substring(8, 10)
                + "-" + pds.substring(0, 4);
            // Process the content so that it displays nicely.
            var staticContent = toStaticHTML(post.querySelector(
                "content").textContent);
            // Store the post info we care about in the array.
            blogPosts.push({
                group: feed, key: feed.title, title: postTitle,
                author: postAuthor, pubDate: postDate,
                backgroundImage: mediumGray, content: staticContent
            });
        }
    }

})();

Связанные разделы

Шаблоны проектов JavaScript

Шаблоны элементов JavaScript

Добавление данных в шаблон проекта (C#, VB и C++)