如何自定义 Visual Studio 模板数据 (HTML)

[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]

在“中心/透视”、“中心”、“透视”、“网格”和“拆分”模板中,获取应用所需数据的代码位于 data.js 文件中。 该文件表示应用的示例数据源。data.js 文件包含替换动态数据通常所需的静态数据。例如,如果应用发出单个 xhr 请求以获取 RSS 或 JSON 数据,则你需要在 data.js 中包括此代码。包含此处的代码可以方便地使用自己的数据而不会更改显示在模板中的数据模型。

提示  “中心/透视”、“中心”、“透视”、“网格”和“拆分”模板还从支持全球化的 .resjson 文件中检索静态数据。有关详细信息,请参阅将数据绑定到“中心/透视”、“中心”和“透视”模板中的 UI 的示例。

 

将自己的数据添加到应用时需要注意下面几项:

  • 组和项目存在固有链接。应用会认为项目数据组织为多个组。可以在你自己的实现中对两者取消链接,但是需要修改代码使该实现可以完成。本主题将介绍模板数据模型中如何使用组。
  • 为 data.js 中的应用实现自定义数据时,需要确保自定义数据固有的属性名称映射到模板使用的属性名称。可以更改模板使用的名称,但是这需要更多的代码修改。本主题提供了一些操作示例。

项目和组

模板数据存储在 WinJS.Binding.List 中。此代码显示了 data.js 文件中列表的声明。

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

项数据的数组(在此示例中为 sampleItems)通过 push 函数传递到 WinJS.Binding.List,如此处所示:

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

 

WinJS.Binding.ListcreateGrouped 函数指定如何使用组密钥和项目组值来分组项目。此函数在 data.js 中调用。keygroup 都是在示例数据数组中指定的属性名称。

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;
    });
}

提示  调用 createFiltered 的函数(如 getItemsFromGroup)创建 WinJS.Binding.List 的新投影,如果你导航离开某个页面,则可能需要释放返回的对象。若要释放对象,请调用 WinJS.Binding.List.dispose 方法。

 

Windows JavaScript 库 define 函数通过指定名为 Data 的命名空间以及一组公用成员函数,公开在应用中使用的数据。

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

如果你希望为应用中的各个页面定义不同的数据源,或不同的数据模型,则需要在 JavaScript 代码中替换对这些成员的所有调用。

将组和项目数据绑定到 UI

下列代码显示的是 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 属性被分配给 ListView 控件的 itemDataSource 属性。

在模板中,数据通常绑定到 init 函数或 ready 函数中的 UI,这两个函数均在与每个 HTML 页面关联的 .js 文件中定义。以下代码包含在 split.html 的 init 函数中。在此代码中,应用获取一个组引用,然后调用 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 属性指定一个类名称为 itemtemplate 的 DIV 元素。

itemTemplate: select('.itemtemplate')

WinJS 模板基于 WinJS.Binding.Template,用于格式化并显示多个数据实例。网格和拆分模板中最常用的模板是用于在 ListView 中显示项目的项模板。如每个 WinJS 模板对象一样,通过添加一个 data-win-control 属性并将其设置为 WinJS.Binding.Template 来声明此模板。此处是 split.html 中 itemtemplate 的 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 中明确命名。在前面的 itemtemplate HTML 代码中,你可以找到 titlesubtitle 等属性。如果你的自定义应用数据不使用这些属性名称,则需要执行下列操作之一:

  • 将你的数据映射到这些属性名称(一般在 data.js 中),或
  • 修复模板代码中这些属性的所有 HTML 和 .js 代码引用,以使它们符合你的数据中使用的属性名称。模板中使用的属性包括:
    • titlesubtitledescriptionbackgroundImage(组和项目属性)
    • groupcontent(项目属性)
    • key(组属性)

遵循同样的 WinJS 模板模式,“网格应用”模板也在它的一些 HTML 页中使用 headerTemplate

将数据绑定到“中心/透视”、“中心”和“透视”模板中的 UI 的示例

在 Visual Studio 中,“中心/透视”、“中心”和“透视”项目模板演示了如何实现两种不同的数据源:

  • 存储在 .resjson 资源文件中的全球化静态数据。此数据在应用的某些部分(PivotItemHubSection 控件)中使用。
  • data.js 中的示例数据,用于表示数据模型。此文件与在“网格”和“拆分”模板中的文件相同。此示例数据在应用的其中一个部分的 ListView 控件中使用。

HTML 中的声明性函数最初用于获取示例数据,并且数据模型在默认情况下同步。若要自定义模板以在所有部分中使用动态数据,则需要对 hub.html、hub.js 和其他文件进行少量更改。以下示例应用显示了如何自定义“中心/透视”和“中心”模板以支持异步数据:

由于 .resjson 文件中的全球化数据可以轻松替换,因此示例应用不修改此资源文件。在该示例应用中,<img> 元素的数据和“中心/透视”部分中存在的 ListView 控件会进行异步检索。

有关在 .resjson 文件中提供全球化数据的详细信息,请参阅快速入门:翻译 UI 资源

若要支持将异步数据绑定到“中心/透视”的 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,目的是避免绑定未准备好的数据。稍后我们将在数据绑定函数中设置数据源(_bindDatabindListView,具体取决于示例应用)。

在数据可用后调用数据绑定函数。要启用此函数,我们将为 data.js 的示例应用中定义的数据模型 dataReady 事件添加一个侦听器。


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

该应用从 onDataCompleted 事件处理程序(未显示)调用数据绑定函数。“中心”模板示例 _bindData 函数的代码如此处所示。在此代码中,我们设置 ListViewitemDataSource 属性。


_bindData: function (context, grp1Items, grp2Items) {

    var self = context;

    // . . .

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

    // . . .   

},

如果使用“后退”按钮导航至该页面,那么将直接从页面的初始化函数调用数据绑定函数,因为不需要等待新数据。

提示  在“中心”模板代码中,要为 ListView 元素(存储在 _section3lv 中)查询 DOM,应用将从“中心”控件的 loadingstatechanged 事件处理程序调用 _hubReady 函数。只有在中心页完成加载后,此事件才会激活。使用此事件处理程序可查询 DOM,以获取与 ListView 关联的嵌套 DIV 元素。

 

有关使异步数据在“中心/透视”和“中心”模板中有效的完整代码,请参阅使用“中心/透视”模板的 JSON Web 阅读器使用“中心”模板的 JSON Web 阅读器。除了此处介绍的自定义内容之外,我们还对示例应用进行了如下更改:

  • 在数据模型 (data.js) 中加入了代码,以便使用 xhr 请求来检索数据并分析 JSON 数据(来自 Flickr)。
  • 在数据模型中加入了代码,以便处理多个数据请求以及在数据返回时激活 dataReady 事件。
  • 在 UI 中加入了一个输入框来请求新数据。
  • 加入了一个进度条来显示数据请求的状态。
  • 为输入框和进度条添加了 CSS 样式。
  • 加入了函数以在“中心”控件完全加载后初始化页面(例如 _hubReady_hubReadyPhone)。
  • 修改了“中心/透视”或“中心”的 <img> 元素以支持单击事件(修改的文件特定于模板)。
  • 修改了文件以将异步数据绑定到“中心/透视”或“中心”的 <img> 元素(修改的文件特定于模板)。
  • 修改了 hub.js 以支持从“中心”的 <img> 元素导航到图像(修改的文件特定于模板)。
  • 修改了 item.html 和 item.js,以便支持查看单个图像。

将数据绑定到 UI(网格和拆分模板)的示例

此部分显示如何在“网格”和“拆分”项目模板中实现自己的数据源。此处的示例代码使用 xhr 请求生成 RSS 数据。

要点  若要在“中心”模板中实现异步数据,请参阅将数据绑定到“中心”模板的 UI。

 

更新 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 函数:sampleGroupssampleItems

    我们将用 RSS 数据替换此数据。大部分的占位符变量我们都不需要使用,如 groupDescription,但需要重复使用占位符图像(lightGraymediumGray)才能使新代码生效。

  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 中指定分组的代码 —groupKeySelectorgroupDataSelector 函数。

    因为我们已更改模板使用的一些属性名称,所以需要对 HTML 页进行一些更新。特别是,对于引用一个项目(非组)的任何 subtitle 属性,需要将 subtitle 更改为 author。对于引用一个项目的任何 description 属性,需要将 description 更改为 pubDate

    若要在 UI 中实现这些更改,请参阅下列部分之一:

    • 将示例数据绑定到“拆分”模板中的 UI
    • 将示例数据绑定到“网格”模板中的 UI

将示例数据绑定到“拆分”模板中的 UI

  1. 若要在“拆分”模板中使用示例代码,请打开 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。

    在 HTML 代码中定义的 WinJS 项模板包含任意 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 调试应用。

    可以立即看到页面标题,但是检索源数据时有短暂的延迟。满足所有承诺时,可以在主页看到每个博客。单击其中一个博客,以查看主视图/详细信息视图中的博客文章。

将示例数据绑定到“网格”模板中的 UI

在执行以下步骤之前,请更新 data.js 项目文件,如将数据绑定到 UI 的示例中所述。

  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 阅读器。有关“中心”模板的 data.js 文件,请参阅使用“中心”模板的 JSON Web 阅读器


(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++)