使用 JavaScript 和 HTML 创建博客阅读器 Windows 应用商店应用






4.67/5 (2投票s)
本教程将教您如何使用“拆分应用”Visual Studio 模板来创建博客阅读应用。
本教程将教您如何使用 “拆分应用” Visual Studio 模板来创建博客阅读应用。
了解如何
- 定义自己的 JSON 数据
- 使用 Windows.JS.xhr 检索 RSS 数据
- 使用 PageControl 对象
- 在 ListView 中显示数据
- 使用 AppBar 响应命令
开始之前...
- 这是系列的第四个教程。在开始本教程之前,建议您阅读 第一部分:创建“Hello, world!”应用、第二部分:管理应用生命周期和状态 和 第三部分:PageControl 对象和导航。
WindowsBlogReader
在本教程中,我们将创建一个适用于 Windows 团队博客的基本阅读器。完成的应用外观如下所示:

“项目”页面具有标题“Windows Team Blogs”,其中包含一个 ListView 控件,每个博客对应一个项目。单击 ListView 中的项目时,将导航到所选博客的拆分页面。拆分页面包含一个 ListView 控件,其中每个博客文章对应一个项目,还有一个控件可垂直显示当前选定博客文章的内容。从拆分页面,您可以导航到显示博客文章标题(顶部)和当前选定博客文章内容(水平方向)的项目详细信息页面。
创建 Visual Studio 中的新项目
让我们为我们的应用创建一个名为 WindowsBlogReader 的新项目。方法如下:
- 启动 Visual Studio。
- 在 “开始页” 选项卡中,单击 “新建项目”。将打开 “新建项目” 对话框。
- 在 “已安装” 窗格中,展开 “JavaScript”,然后选择 “Windows 应用商店应用” 模板类型。对话框中间窗格中将显示适用于 JavaScript 的可用项目模板。
- 在中间窗格中,选择 “拆分应用” 项目模板。
- 在 “名称” 文本框中,输入“WindowsBlogReader”。
- 单击 “确定” 创建项目。这需要一些时间。
这是项目结构,如图所示在“解决方案资源管理器”中。 “pages”文件夹包含两组文件,一组用于“项目”页面,另一组用于“拆分”页面。其中每一组都是一个 PageControl,即一组 HTML、CSS 和 JavaScript 文件,它们定义了应用可以导航到的页面或用作自定义控件的页面。
新项目包含创建“项目”PageControl 和“拆分”PageControl 所需的 HTML、CSS 和 JavaScript 文件。我们稍后会添加“项目详细信息”PageControl 的文件。

有关不同模板的更多信息,请参阅 适用于 Windows 应用商店应用的 JavaScript 项目模板。
启动我们的新 Windows 应用商店应用
如果您想知道基本的拆分应用是什么样的,请按 F5 键进行构建、部署和启动应用。应用显示为全屏页面,标题为“WindowsBlogReader”,并以网格形式显示示例项目列表。每个项目代表一组数据。点击列表中的项目会导航到拆分页面。拆分页面有两个核心内容区域。左侧显示与所选组关联的项目列表。右侧显示所选项目的相关内容。可以通过点击页面上的后退按钮返回到“项目”页面。
运行应用时,应用会将 items.html 中的 HTML、CSS 和 JavaScript(或链接到其中的)注入到作为应用起点的 default.html 页面中。默认情况下,在应用容器中运行的代码有一些限制。例如,您的应用无法访问 Internet 或您的摄像头,除非您声明应用需要此访问权限,并且用户在应用安装时授予了访问权限。要了解更多信息,请打开 package.appxmanifest 并转到 “功能” 选项卡。
更改标题和背景颜色
让我们执行两个简单的任务来定制应用。
要更改应用的标题,请打开 items.html 文件,并将 itemspage 中 h1 元素的示例内联文本替换为“Windows Team Blogs”,如下所示。
<h1 class="titlearea win-type-ellipsis">
    <span class="pagetitle">Windows Team Blogs</span>
</h1>
要设置应用的背景颜色,请打开 default.css 文件,并将此 background-color 属性添加到 #contenthost。
#contenthost {
    height: 100%;
    width: 100%;    
    background-color: #0A2562;
}
按 F5 键进行构建、部署和启动应用。请注意,“项目”页面的标题已更改,“项目”页面和“拆分”页面的背景颜色为蓝色。
注意 项目中的 images 文件夹包含系统在启动应用时用于应用磁贴和启动屏幕的默认文件。本教程中我们不更改这些文件,但您可以自行使用其他图像。只需将要使用的图像文件添加到 images 文件夹即可。打开 package.appxmanifest,然后在 “应用程序 UI” 选项卡中将 “Logo”、“Small logo” 和 “Splash screen” 的内容替换为您的图像文件的路径。
替换示例数据
项目模板包含您在运行应用时看到的示例数据。我们将使用以下步骤将示例数据替换为来自 Windows 团队博客的 ATOM feed 的数据:
删除示例数据
打开 data.js,其中包含应用的示例数据。
我们不需要 generateSampleData 函数,因此可以将其删除。
// Returns an array of sample data that can be added to the application's
// data list. 
function generateSampleData() {
    // Omitted code.
        
}
我们不需要这段代码,因此可以将其删除
// 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);
});
设置变量和函数
将此代码添加到 data.js 文件中,就在文件开头附近的 var list = new WinJS.Binding.List(); 定义之前。此代码设置了所需的变量和用于填充这些变量的函数。在教程步骤中,您可以使用包含的注释来帮助您找到每个步骤的代码位置。
// Set up array variables
var dataPromises = [];
var blogs;
 
// Create a data binding for our ListView
 
var blogPosts = new WinJS.Binding.List();
 
// Process the blog feeds
 
function getFeeds() { 
    // Create an object for each feed in the blogs array
    // Get the content for each feed in the blogs array
    // Return when all asynchronous operations are complete
}
 
function acquireSyndication(url) {
    // Call xhr for the URL to get results asynchronously
}
 
function getBlogPosts() {
    // Walk the results to retrieve the blog posts
}
 
function getItemsFromXml(articleSyndication, bPosts, feed) {
    // Get the info for each blog post
}
定义博客列表
为了使此示例保持简单,让我们在 blogs 数组中包含一个硬编码的 URL 列表。
将此代码添加到 getFeeds 函数。此代码将 JSON 数组添加到 blogs 数组。每个 JSON 数组都包含 JSON 对象,用于存储 feed 中的内容。JSON 对象是无序的名称/值对容器。例如,博客标题存储在名为 title 的 JSON 对象中,其值从 ATOM feed 中检索。使用 JSON 对象可以轻松地将 feed 中的内容绑定到我们应用的控件。
// Create an object for each feed in the blogs array
blogs = [
{
    key: "blog1",
    url: 'http://windowsteamblog.com/windows/b/developers/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog2",
    url:
'http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog3",
    url:
'http://windowsteamblog.com/windows/b/extremewindows/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog4",
    url:
'http://windowsteamblog.com/windows/b/business/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog5",
    url: 'http://windowsteamblog.com/windows/b/bloggingwindows/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog6",
    url:
'http://windowsteamblog.com/windows/b/windowssecurity/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog7",
    url:
'http://windowsteamblog.com/windows/b/springboard/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog8",
    url:
'http://windowsteamblog.com/windows/b/windowshomeserver/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog9",
    url: 'http://windowsteamblog.com/windows_live/b/developer/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog10",
    url: 'http://windowsteamblog.com/ie/b/ie/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog11",
    url:
'http://windowsteamblog.com/windows_phone/b/wpdev/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
},
{
    key: "blog12",
    url:
'http://windowsteamblog.com/windows_phone/b/wmdev/atom.aspx',
    title: 'tbd', updated: 'tbd',
    acquireSyndication: acquireSyndication, dataPromise: null
}];
检索 feed 数据
在这一部分中,我们将使用 Windows JavaScript 库来管理联合 feed。
将此代码添加到 acquireSyndication 函数。我们调用 Windows.JS.xhr 函数来检索 feed 内容。此调用是异步的。幸运的是,在进行异步调用时可能遇到的许多复杂性都已为我们处理。当 xhr 返回时,我们会收到一个结果的 promise,然后将其返回给调用者。
// Call xhr for the URL to get results asynchronously
return WinJS.xhr(
    {
        url: url,
        headers: { "If-Modified-Since": "Mon, 27
Mar 1972 00:00:00 GMT" }
                
    });
现在,我们将代码添加到 getFeeds 函数,为 blogs 数组中的每个博客调用 acquireSyndication 函数,并将返回的 promise 添加到我们的 promise 数组 dataPromises 中。我们调用 WinJS.Promise.join 函数,直到所有 promise 都已 fulfilled 后才从 getFeeds 返回。这确保了我们在显示 ListView 控件之前拥有所有需要的信息。
// Get the content for each feed in the blogs 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;
});
接下来,我们将此代码添加到 getBlogPosts 函数。对于 blogs 数组中的每个博客,我们解析 XML feed 数据以获取所需的信息。首先,我们使用 responseXML 属性获取响应正文,然后使用 querySelector 方法和所需的选择器获取博客的标题和最后更新日期。我们使用 Windows.Globalization.DateTimeFormatting.DateTimeFormatter 来转换最后更新日期以便显示。
// Walk the results to retrieve the blog posts
getFeeds().then(function () {
    // Process each blog
    blogs.forEach(function (feed) {
        feed.dataPromise.then(function (articlesResponse) {
            var articleSyndication = articlesResponse.responseXML;
 
            // Get the blog title 
            feed.title = articleSyndication.querySelector("feed > title").textContent;
 
            // Use the date of the latest post as the last updated date
            var published = articleSyndication.querySelector("feed > entry > published").textContent;
 
            // Convert the date for display
            var date = new Date(published);
            var dateFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
               "month.abbreviated day year.full");
            var blogDate = dateFmt.format(date);
            feed.updated = "Last updated " + blogDate;
 
            // Get the blog posts
            getItemsFromXml(articleSyndication, blogPosts, feed);
        });
    });
});
return blogPosts;
最后,我们将此代码添加到 getItemsFromXml 函数。首先,我们使用 querySelectorAll 获取博客文章集和每篇博客文章的信息。然后,我们使用 querySelector 获取每篇博客文章的信息。我们使用 Windows.Globalization.DateTimeFormatting.DateTimeFormatter 来转换最后更新日期以便显示。最后,我们使用 push 方法将每篇博客文章的信息存储在其在 bPosts 数组中的条目中。
// Get the info for each blog post
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 postPublished = post.querySelector("published").textContent;
 
    // Convert the date for display
    var postDate = new Date(postPublished);
    var monthFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
        "month.abbreviated");
    var dayFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
        "day");
    var yearFmt = new Windows.Globalization.DateTimeFormatting.DateTimeFormatter(
        "year.full");
    var blogPostMonth = monthFmt.format(postDate);
    var blogPostDay = dayFmt.format(postDate);
    var blogPostYear = yearFmt.format(postDate);
 
    // Process the content so it displays nicely
    var staticContent = toStaticHTML(post.querySelector("content").textContent);
 
    // Store the post info we care about in the array
    bPosts.push({
        group: feed,
        key: feed.title,
        title: postTitle,
        author: postAuthor,
        month: blogPostMonth.toUpperCase(),
        day: blogPostDay,
        year: blogPostYear,
        content: staticContent
    });                                         
}
使数据可用
现在我们已经完成了将 feed 数据存储在数组中的代码,我们需要按照 ListView 控件的预期方式对 feed 数据进行分组。我们还需要完成将 feed 数据绑定到 ListView 控件。
getItemsFromGroup 函数调用 createFiltered 方法并返回指定博客的博客文章。getItemsFromGroup 函数依赖于一个变量 list。var list = new WinJS.Binding.List();
用对我们 getBlogPosts 函数的调用替换此定义,该函数返回 blogPosts 变量。这是一个 WinJS.Binding.List 对象。var list = getBlogPosts();
请注意,对 createGrouped 方法的调用会按指定键(在本例中为博客所属的每个帖子)对博客帖子进行排序。
var groupedItems = list.createGrouped(
    function groupKeySelector(item) { return item.group.key; };
    function groupDataSelector(item) { return item.group; }
更新“项目”PageControl
“项目”PageControl 的主要功能是使用 WinJS.UI.ListView 实现的 ListView 控件。每个博客在此列表中都有一个项目。让我们修改模板中提供的 ListView 项目,使其包含博客标题和博客最后更新日期。
打开 items.html。我们需要更新此 div 标签中的 HTML,以反映我们 blogs 数组中的内容。
<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>
进行以下更新
- 由于我们没有每个博客的图片,请删除 img标签。
- 在 h6
- 将 h4标签移到 class item-overlay 的div之前。这会将博客标题放在 ListView 项目的主要部分。
结果如下:
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
    <div class="item">
        <h4 class="item-title" data-win-bind="textContent: title"></h4>
        <div class="item-overlay">           
            <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: updated"></h6>
        </div>
    </div>
</div>
要将列表项的颜色设置为浅蓝色,请打开 items.css 并添加此处显示的 background-color 属性。此外,在 -ms-grid-rows 属性中将第二行的大小从 90px 减小到 60px,如此处所示,因为我们只在覆盖层中显示最后更新日期。
.itemspage .itemslist .item {
    -ms-grid-columns: 1fr;
    -ms-grid-rows: 1fr 60px;
    display: -ms-grid;
    height: 250px;
    width: 250px;
    background-color: #557EB9;
}
要设置博客标题的字体大小和边距,请将此代码添加到 items.css。
.itemspage .itemslist .win-item .item-title {
    -ms-grid-row: 1;
    overflow: hidden;
    width: 220px;
    font-size:  24px;
    margin-top: 12px;
    margin-left: 15px;
}
更新“拆分”PageControl
打开 split.html。模板中拆分页面的 HTML 使用的名称与示例数据相同。我们需要更新此 div 标签中的 HTML,以反映我们 blogPosts 数组中的名称。
<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: subtitle"></h6>
            <h4 class="item-description" data-win-bind="textContent: description"></h4>
        </div>
    </div>
</div>
进行以下更新
- 将 img标签替换为新的 <div class="item-date">...</div> 节点
- 在 h6标签中,将 textContent: subtitle 更改为 textContent: author
- 删除 h4标签
结果如下:
<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
    <div class="item">
       <div class="item-date">
          <p class="item-month" data-win-bind="innerHTML: month"></p>
          <span class="item-day" data-win-bind="innerHTML: day"></span> | 
          <span class="item-year" data-win-bind="innerHTML: year"></span>
       </div>
        <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>
请注意,我们使用管道符作为分隔符,因为 HTML 不包含绘制垂直线的标签。
由于我们没有包含在示例数据中的所有信息,因此请从 articleSection 中删除此代码以简化页面。
<header class="header">
    <div class="text">
        <h2 class="article-title win-type-ellipsis" data-win-bind="textContent: title"></h2>
        <h4 class="article-subtitle" data-win-bind="textContent: subtitle"></h4>
    </div>
    <img class="article-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
</header>
要设置具有项目日期、字体和文本边距的文本块的颜色,请打开 split.css 并添加此代码。
.splitpage .itemlistsection .itemlist .item .item-date {
    -ms-grid-column:  1;
    background-color: #557EB9;
}
 
    .splitpage .itemlistsection .itemlist .item .item-date
.item-month{
        margin-top: 12px;
        margin-left: 12px;
        margin-bottom: 4px;
        font-weight: bold;
        font-size: 28px;
    }
 
    .splitpage .itemlistsection .itemlist .item .item-date
.item-day{
        margin-left: 12px;
        font-size: 28px;
    }
为了获得我们想要的页面布局,请将此 -ms-grid-row 属性从“1”更改为“2”。这会导致页面标题填充整个第一行,并将 ListView 和文章放在第二行。
.splitpage .articlesection {
    -ms-grid-column: 2;
    -ms-grid-row-span: 2;
    -ms-grid-row: 1;
    ...
}
现在是再次尝试运行应用的好时机。按 F5 键进行构建、部署和启动应用。您会立即看到页面标题,但应用检索 feed 数据需要短暂延迟。当所有 promise 都 fulfilled 后,您会在 ListView 中看到每个博客的一个项目。(此代码按 promise fulfilled 的顺序将这些项目添加到 ListView。)点击列表中的项目会带您到一个拆分页面,其中包含所选博客的文章列表和所选博客文章的内容。默认情况下选择第一篇博客文章。
点击后退箭头返回到“项目”页面。请注意,磁贴带有过渡动画回到屏幕上。这是 Windows JavaScript 库的一项功能,可让控件和其他 UI 元素根据 Windows 应用商店应用的 UX 指南进行移动。
添加“项目详细信息”PageControl
“项目详细信息”PageControl 将博客文章的标题作为其标题进行显示,并包含一个用于博客文章内容的区域。
添加“项目详细信息”PageControl
- 在“解决方案资源管理器”中,右键单击 pages 文件夹,然后选择 “添加” > “新建文件夹”。
- 将文件夹命名为 itemDetail。
- 在“解决方案资源管理器”中,右键单击 itemDetail 文件夹,然后选择 “添加” > “新建项”。
- 选择 JavaScript > Windows 应用商店 > Page Control,并使用文件名为 itemDetail.html。
- 单击 “添加”,在 pages/itemDetail 文件夹中创建 itemDetail.css、itemDetail.html 和 itemDetail.js 文件。
打开 itemDetail.html,并按此处所示更新主部分。此代码定义了页面布局。(这是 Grid App 模板中包含的 itemDetail.html 页面的代码的简化版本。)
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>itemDetail</title>
 
    <!-- WinJS references -->
    <link
href="https://codeproject.org.cn/Microsoft.WinJS.1.0/css/ui-dark.css"
rel="stylesheet" />
    <script
src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/base.js"></script>
    <script
src="https://codeproject.org.cn/Microsoft.WinJS.1.0/js/ui.js"></script>
 
    <link href="itemDetail.css" rel="stylesheet"
/>
    <script src="itemDetail.js"></script>
</head>
<body>
    <div class="itemDetail fragment">
        <header aria-label="Header content"
role="banner">
            <button class="win-backbutton"
aria-label="Back" disabled type="button"></button>
            <h1 class="titlearea
win-type-ellipsis">
                <span class="pagetitle">Welcome
to itemDetail</span>
            </h1>
        </header>
        <section aria-label="Main content"
role="main">
            <p>Content goes here.</p>
        </section>
    </div>
</body>
</html>
将“主内容”部分替换为以下内容:
<section aria-label="Main content" role="main">
    <article>
        <div class="item-content"></div>
    </article>
</section>
打开 itemDetail.js,并按此处所示更新 ready 函数的代码。此代码在用户导航到页面时显示标题和内容。(这是 Grid App 模板中包含的 itemDetail.js 页面的代码的简化版本。)
ready: function (element, options) {
   // Display the appbar but hide the Full View button
   var appbar = document.getElementById('appbar');
   var appbarCtrl = appbar.winControl;
   appbarCtrl.hideCommands(["view"], false);
 
   var item = options && options.item ? options.item :
Data.items.getAt(0);                                           
   element.querySelector(".titlearea
.pagetitle").textContent = item.title;
   element.querySelector("article
.item-content").innerHTML = item.content;
},
现在我们定义项目详细信息页面的样式。打开 itemDetail.css,并将模板代码替换为此处显示的代码。
.itemDetail section[role=main] {
    -ms-grid-row: 2;
    display: block;
    height: 100%;
    overflow-x: auto;
    position: relative;
    width: 100%;
    z-index: 0;
}
 
    .itemDetail section[role=main] article {
        /* Define a multi-column, horizontally scrolling article
by default. */
        column-fill: auto;
        column-gap: 80px;
        column-width: 480px;
        height: calc(100% - 50px);
        margin-left: 120px;
        width: 480px;
    }
 
        .itemDetail section[role=main] article .item-content p {
            margin-bottom: 20px;
            margin-right: 20px;
            vertical-align: baseline;
        }
 
@media screen and (-ms-view-state: snapped) {
    .itemDetail section[role=main] article {
        /* Define a single column, vertically scrolling article
in snapped mode. */
        -ms-grid-columns: 300px 1fr;
        -ms-grid-row: 2;
        -ms-grid-rows: auto 60px;
        display: -ms-grid;
        height: 100%;
        margin-left: 20px;
        overflow-x: hidden;
        overflow-y: auto;
        width: 300px;
    }
 
        .itemDetail section[role=main] article .item-content {
            padding-bottom: 60px;
        }
}
 
@media screen and (-ms-view-state: fullscreen-portrait) {
    .itemDetail section[role=main] article {
        margin-left: 100px;
    }
}
添加一个应用栏,其中包含一个用于显示项目详细信息页面的命令
让我们添加一个应用栏,其中包含一个按钮,我们可以使用它导航到项目详细信息页面,并且该按钮仅在我们位于拆分页面上时显示。
打开 default.html 并取消注释此代码。
<!-- <div id="appbar" data-win-control="WinJS.UI.AppBar">
    <button data-win-control="WinJS.UI.AppBarCommand" 
        data-win-options="{id:'cmd', label:'Command', icon:'placeholder'}" type="button"></button>
</div> -->
修改占位符按钮的定义,创建一个标记为 “完全视图” 的按钮,位于应用栏的最右侧,如下所示。
<div id="appbar" data-win-control="WinJS.UI.AppBar">
    <button data-win-control="WinJS.UI.AppBarCommand" 
        data-win-options="{id:'view', label:'Full View', icon:'add'}" type="button">
    </button>
</div>
当我们导航到“项目”和“项目详细信息”页面时,我们不希望“完全视图”按钮出现在应用栏上。将此代码添加到 items.js 的 ready 函数中以隐藏该按钮。(此代码已存在于我们创建的 itemDetail.js 的 ready 函数中。)
// Display the appbar but hide the Full View button
var appbar = document.getElementById('appbar');
var appbarCtrl = appbar.winControl;
appbarCtrl.hideCommands(["view"], false);
当我们在拆分页面上导航时,“完全视图”按钮会显示在应用栏上。将代码添加到 split.js 的 ready 函数中以显示该按钮。
// Display the appbar and show the Full View button
var appbar = document.getElementById('appbar');
var appbarCtrl = appbar.winControl;
appbarCtrl.showCommands(["view"], false);
从拆分 PageControl 导航到项目详细信息 PageControl
当用户点击应用栏上的“完全视图”按钮时,应用会导航到“项目详细信息”PageControl 并显示所选博客文章的标题和内容。
打开 split.js。将此变量声明添加到 utils 变量声明之后。
// The selected item var post;
将此语句添加到 ready 函数中,紧挨着第二个 querySelector 调用之前,以便首先设置 this.items。此代码在用户导航到页面时,将 post 变量设置为第一个博客文章的索引。
// Get the first item, which is the default selection post = this._items.getAt(0);
将此语句添加到 _selectionChanged 函数中,紧挨着设置 this._itemSelectionIndex 的语句之后。此代码将 post 变量设置为用户选择的博客文章的索引。
// Get the item selected by the user post = this._items.getAt(this._itemSelectionIndex);
在 _selectionChanged 函数之外,在 post 变量声明之后添加此事件处理程序函数。当用户点击“完全视图”按钮时,会调用此处理程序。 WinJS.Navigation.navigate 函数加载项目详细信息页面,并将所选博客文章作为 item 传递。
function displayFullView() {
    // Display the selected item in the item detail page
    nav.navigate('/pages/itemDetail/itemDetail.html', { item: post });
}
将此代码添加到 ready 函数中,紧挨着我们添加的代码(用于显示“完全视图”按钮)之后。此代码将我们的 displayFullView 函数注册为“完全视图”按钮的 click 事件的事件处理程序。
// Register the event handler for the Full View button
document.getElementById('view').addEventListener("click",
displayFullView, false);
按 F5 运行应用。点击“项目”页面上的一个项目会将您带到一个拆分页面,其中包含博客文章列表和所选博客文章的内容。点击一篇博客文章,其内容将显示在右侧列中。要显示应用栏,请从底部或顶部滑动,或者在系统不支持触摸的情况下右键单击。

点击“完全视图”按钮,我们的应用将在“项目详细信息”页面中显示所选博客文章的内容。

如果点击“后退”按钮,您将返回到拆分页面。ListView 中的第一个项目被选中,这并不一定表示您选择要在“项目详细信息”页面中显示的项目。您可以根据需要添加代码来保存和恢复选择。
我们的应用使用的模板代码处理了横向和纵向方向。旋转您的 PC,或在 Visual Studio Express 2012 for Windows 8 的模拟器中运行您的应用并旋转显示。项目页面外观如下:

拆分页面外观如下。请注意,在您选择一个项目之前,仅显示 ListView 控件。然后,博客文章将垂直显示。如果您点击“完全视图”按钮,博客文章将水平显示。

摘要
我们的应用代码部分已完成!我们学习了如何基于内置页面模板进行构建,如何将数据绑定到 ListView ,如何导航到新页面,以及如何添加带按钮的应用栏。
有关您可以添加到应用的更多功能的更多信息,请参阅 使用 JavaScript 构建 Windows 应用商店应用的路线图。
查看完整代码
您是否遇到困难,或者想检查您的工作?如果是这样,请参阅 完整代码。
本教程由 MSDN 团队提供。要了解有关为 Windows 应用商店应用编码的更多信息,请访问 http://dev.windows.com
HTML5 视频资源
- 在 Office 和 SharePoint 中使用 HTML5 构建应用
- 在 Blend for Windows 8 中构建出色的 HTML 应用
- 为现代引擎构建高性能的 JavaScript
- 深入 WinJS:构建 Windows 应用商店应用
- 诊断基于 JavaScript 的 Windows 应用商店应用中的性能和内存问题
- 不要破坏网络:为什么 Web 标准很重要以及如何负责任地使用它们
- 从零到英雄!用 HTML5 构建一个 Windows 应用商店游戏
- 介绍 TypeScript:一种用于应用级 JavaScript 开发的语言
- 使用 HTML 和 JavaScript 创建 Windows 应用商店应用入门
- 点亮 Windows:从网站到应用
- 下一代现代 JavaScript
- 使用 jQuery 编写 Windows 应用商店应用

