如何显示不同尺寸的项 (HTML)

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

默认情况下,ListView 为列表中每个项分配相同的大小。使用网格布局时,你可以修改此行为,并通过使某些大小不同的项跨多个单元格来显示这些项。

你需要了解的内容

技术

先决条件

说明

关于 ListView 中的单元格和大小调整

研究代码之前,先了解 ListView 如何调整项大小很有帮助。

默认情况下,ListView 为其所包含的每个项分配了相同的大小。下面的 ListView 所包含的项大小均相同。

包含的项大小相同的 ListView

下面是相同的 ListView,但有一个单元格突出显示。

ListView 中的一个单元格

该单元格的大小取决于 ListView 中第一个项的大小。当 ListView 包含大小不同的项时,它仍将基于第一个项的大小分配单元格大小。因此,如果一个项大于其他项,则系统将对其进行裁剪以与其他 ListView 项的大小匹配。

包含的项大小不同的 ListView

你可以启用单元格跨并功能更改这一行为。从而,一个项即可占用多个单元格。在此示例中,启用了单元格跨并功能,较大的项占用 5 个单元格,而非一个单元格。

启用单元格跨并功能的 ListView

启用单元格跨并功能时,还可明确指定基础单元格的大小。我们建议将 ListView 中的每个项目大小设定为基础单元格的倍数。在下一个示例中,对较大的项进行了修改,使其高度为基础单元格的两倍,但宽度相同。

包含的项中有很多基础单元格大小相同的 ListView

以下介绍如何创建包含三种不同大小的项的 ListView

第 1 步:创建你的数据与 ListView

首先,创建一个数据源和一个 ListView

  1. 在 JavaScript 文件中,为 ListView 定义一个数据源。此示例通过 JSON 对象数组创建 List,并使用 WinJS.Namespace.define 通过名为 DataExamples 的命名空间将其公开,从而使其可公开访问。

    该数据与我们在其他主题(例如快速入门:添加 ListView)中列举的示例类似,不过该数据增加了一个字段,即:type 字段。 该字段有三个可能值:"smallListIconTextItem"、"mediumListIconTextItem" 和 "largeListIconTextItem"。在后续步骤中,我们将使用此字段分配 CSS 类,用于确定每个项的大小。

    (function () {
        "use strict";
    
        var myCellSpanningData = new WinJS.Binding.List([
                { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", type: "smallListIconTextItem" },
                { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png", type: "mediumListIconTextItem" },
                { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png", type: "largeListIconTextItem" },
                { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png", type: "mediumListIconTextItem" },
                { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png", type: "smallListIconTextItem" },
                { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png", type: "smallListIconTextItem" },
                { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", type: "mediumListIconTextItem" },
                { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png", type: "mediumListIconTextItem" },
                { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png", type: "smallListIconTextItem" },
                { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png", type: "smallListIconTextItem" },
                { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png", type: "smallListIconTextItem" },
                { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png", type: "smallListIconTextItem" },
                { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", type: "smallListIconTextItem" },
                { title: "Lavish Lemon Ice", text: "Sorbet", picture: "images/60Lemon.png", type: "smallListIconTextItem" },
                { title: "Marvelous Mint", text: "Gelato", picture: "images/60Mint.png", type: "mediumListIconTextItem" },
                { title: "Creamy Orange", text: "Sorbet", picture: "images/60Orange.png", type: "smallListIconTextItem" },
                { title: "Succulent Strawberry", text: "Sorbet", picture: "images/60Strawberry.png", type: "largeListIconTextItem" },
                { title: "Very Vanilla", text: "Ice Cream", picture: "images/60Vanilla.png", type: "mediumListIconTextItem" }
        ]);
    
    
    
        WinJS.Namespace.define("DataExamples",
            {
                myCellSpanningData: myCellSpanningData
            });
    
    })();
    

    (如果编码时想使用此示例中所用的图像,你可以通过下载 ListView 项目模板示例获取这些图像。)

  2. 在 HTML 文件中,创建一个使用单元格跨并功能布局的 ListView。将其 itemDataSource 属性设置为你在上一步中所创建的数据源。

    <div id="myListView" 
        data-win-control="WinJS.UI.ListView" 
        data-win-options="{ 
            itemDataSource: DataExamples.myCellSpanningData.dataSource, 
            layout: {  
                type: WinJS.UI.CellSpanningLayout 
            } 
        }"
    ></div>
    

第 2 步:定义基础单元格大小并启用单元格跨并功能

现在,我们需要定义基础单元格的大小。

若要让 ListView 使用单元格跨并功能布局,请创建一个 CellSpanningLayout 对象并使用该对象设置 ListView 控件的 layout 属性。若要启用单元格跨并功能并定义基础单元格的大小,请创建一个用于提供此信息的 groupInfo 函数,并使用此函数设置 CellSpanningLayout 对象的 groupInfo 属性。我们定义的 groupInfo 函数所返回的对象必须包含以下属性。

  • enableCellSpanning
    设置为 true 以启用单元格跨并功能。默认值为 false

  • cellWidth
    基础单元格的宽度。

  • cellHeight
    基础单元格的高度。

对于此示例,我们使用大小为 310×80 像素的基础单元格。

JJ657974.wedge(zh-cn,WIN.10).gif定义基础单元格的大小并启用单元格跨并功能的步骤

  1. 在创建数据所在的 JavaScript 文件中,创建一个 groupInfo 函数,以用于启用单元格跨并功能和定义大小为 310×80 像素的基础单元格。

    // Enable cell spanning and specify
    // the cellWidth and cellHeight for the items
    var groupInfo = function groupInfo() {
        return {
            enableCellSpanning: true,
            cellWidth: 310,
            cellHeight: 80
        };
    };
    
  2. 使用 WinJS.Utilities.markSupportedForProcessing 使你的函数可在 HTML 中访问。

    // Enable cell spanning and specify
    // the cellWidth and cellHeight for the items
    var groupInfo = function groupInfo() {
        return {
            enableCellSpanning: true,
            cellWidth: 310,
            cellHeight: 80
        };
    };
    
    WinJS.Utilities.markSupportedForProcessing(groupInfo);
    

    (默认情况下,鉴于安全考虑,函数和事件处理程序对 Windows JavaScript 库控件不可访问。使用 WinJS.Utilities.markSupportedForProcessing 函数可以覆盖此默认行为。这一操作假设你提供的 HTML 格式正确且可以由 WinJS 处理。有关详细信息,请参阅对基本应用编码。)

    在函数中调用 WinJS.Utilities.markSupportedForProcessing 并不能使其可公开访问。我们将在下一步中介绍如何使其可公开访问。

  3. 通过命名空间使 groupInfo 函数可公开访问。此示例更新我们在第 1.1 步中创建的 DataExamples 命名空间。

    WinJS.Namespace.define("DataExamples",
        {
            groupInfo : groupInfo,
            myCellSpanningData: myCellSpanningData
        });
    
  4. 将你的 ListView 更新为使用 groupInfo 函数。

    <div id="myListView" 
        data-win-control="WinJS.UI.ListView" 
        data-win-options="{ 
            itemDataSource: DataExamples.myCellSpanningData.dataSource, 
            layout: {  
                groupInfo: DataExamples.groupInfo,
                type: WinJS.UI.GridLayout 
            } 
        }"
    ></div>
    

第 3 步:定义占用单个单元格的项的大小

上面,我们已定义基础单元格大小,接下来我们可定义项的大小。我们在第一步定义数据时,包含了一个 type 字段,其中包含项可设置大小(小、中或大)的相关信息。我们可使用此信息来分配项大小。分配大小的最佳方法是使用 CSS 类。无论我们是使用模板函数还是 WinJS.Binding.Template,此方法均有效。

我们的基础单元格宽为 310 像素,高为 80 像素。每个项的总大小必须是基础单元格的倍数。基础单元格大小是指项加上该项的衬距、边距和边框所得出的大小:

ListView 中的一个单元格

以下是基础单元格大小的计算公式:

  • 基础单元格宽度 = 项宽度 + 项水平衬距 + 项水平边距 + 项边框粗细
  • 基础单元格高度 = 项高度 + 项垂直衬距 + 项垂直边距 + 项边框粗细

JJ657974.wedge(zh-cn,WIN.10).gif定义占用单个基础单元格的项的大小

  1. 下面我们定义最小项的大小。在 CSS 文件中,创建一个名为 "smallListIconTextItem" 的级联样式表 (CSS) 类。

    .smallListIconTextItem
    {
    
    }     
    
  2. 最小项仅占一个单元格。我们将项的宽度设置为 300px,高度设置为 70px,衬距设置为 5px。

    .smallListIconTextItem
    {
        width: 300px;
        height: 70px;
        padding: 5px;
        overflow: hidden;
        background-color: Pink;
        display: -ms-grid;
    }    
    

    我们根据公式来检查下这些数字,以确保它们与我们的基础单元格大小匹配。

    • 单元格宽度 = 项宽度 + 左衬距 + 右衬距 + 边框粗细 + 左边距 + 右边距 = 300 + 5px + 5px + 0 + 0 + 0 = 310

    • 单元格高度 = 项高度 + 上衬距 + 下衬距 + 边框粗细 + 上边距 + 下边距 = 70px + 5px + 5px + 0 + 0 + 0= 80

    它们与基础单元格大小匹配,因此,我们可以继续进行下一步。

第 4 步:定义跨 2 个或多个单元格的项的大小

确定跨一个或多个单元格的项的大小时,还必须考虑所跨单元格之间的 win-container 边距。例如,你有一个项水平跨一个单元格,但垂直跨两个单元格,则其总项大小包括第一个单元格的 win-container 下边距和第二个单元格的 win-container 上边距,如下所示。

跨两个单元格的项

以下是跨多个单元格的项的总项大小计算公式:

  • 总项宽度 = number of cells * 基础单元格宽度 + (number of cells - 1) *(win-container 左边距 + win-container 右边距)

  • 总项高度 = number of cells * 基础单元格高度 + (number of cells - 1) * (win-container 上边距 + win-container 下边距)

提示  在默认情况下,win-container 边距为 5 像素。

 

JJ657974.wedge(zh-cn,WIN.10).gif定义垂直跨两个单元格的项的大小的步骤

  1. 使用我们的公式确定总项高度:

    总项高度 = number of cells * 基础单元格高度 + (number of cells - 1) *(win-container 上边距 + win-container 下边距)= 2 * 80 + (2-1) * (5 + 5) = 170

  2. 创建用于指定大小项的 CSS 样式。此示例定义的项高度为 160 像素,衬距为 5 像素,因此其总高度为 160 + 5 + 5 = 170。由于项仅水平跨一个单元格,因此按照在第 3 步中创建的 CSS 类 smallListIconTextItem 设置相同的宽度和衬距。

    .mediumListIconTextItem
    {
        width: 300px;
        height: 160px;
        padding: 5px;
        overflow: hidden;
        background-color: LightGreen;
        display: -ms-grid;
    }
    

JJ657974.wedge(zh-cn,WIN.10).gif定义垂直跨三个单元格的项的大小

  1. 使用我们的公式确定总项高度:

    总项高度 = number of cells * 基础单元格高度 + (number of cells - 1) *(win-container 上边距 + win-container 下边距)= 3 * 80 + (3-1) * (5 + 5) = 260

  2. 创建用于指定大小项的 CSS 样式。此示例定义的项高度为 250 像素,衬距为 5 像素,因此其总高度为 250 + 5 + 5 = 260。

    .largeListIconTextItem
    {
        width: 300px;
        height: 250px;
        padding: 5px;
        overflow: hidden;
        background-color: LightBlue;
        display: -ms-grid;
    }
    

第 5 步:为 CellSpanningLayout 创建项大小函数

除了 groupInfo 函数外,CellSpanningLayout 还需要公开 itemInfo 函数,该函数可确定如何在数据源中调整不同“类型”的项的大小。itemInfo 函数需要返回 JavaScript 对象,该对象包含以下属性:

JJ657974.wedge(zh-cn,WIN.10).gif在 ListView 中定义单独项的大小的步骤

  1. 在创建数据所在的 JavaScript 文件中,创建一个 itemInfo 函数,该函数可返回从数据源检索的项,并返回该项的对应大小和高度。

    // Item info function that returns the size of a cell spanning item
    var itemInfo = WinJS.Utilities.markSupportedForProcessing(function itemInfo(itemIndex) {
        var size = { width: 310, height: 80 };
    
        // Get the item from the data source
        var item = DataExamples.myCellSpanningData.getAt(itemIndex);
        if (item) {
    
            // Get the size based on the item type
            switch (item.type) {
                case "smallListIconTextItem":
                    size = { width: 310, height: 80 };
                    break;
    
                case "mediumListIconTextItem":
                    size = { width: 310, height: 170 };
                    break;
    
                case "largeListIconTextItem":
                    size = { width: 310, height: 260 };
                    break;
    
                default:
            }
        }
        return size;
    });
    

    itemInfo 由对 WinJS.Utilities.markSupportedForProcessing 的调用包装,以使该函数在 HTML 中可访问。

  2. 通过命名空间公开 itemInfo 函数来使其可公开访问。本示例更新我们在第 1.1 步中创建的 DataExamples 命名空间。

    WinJS.Namespace.define("DataExamples",
        {
            myCellSpanningData: myCellSpanningData,
            groupInfo: groupInfo,
            itemInfo: itemInfo
    });
    
  3. 将你的 ListView 更新为使用 itemInfo 函数。

    <div id="myListView" 
        data-win-control="WinJS.UI.ListView" 
        data-win-options="{ 
            itemDataSource: DataExamples.myCellSpanningData.dataSource, 
            layout: {  
                groupInfo: DataExamples.groupInfo,
                itemInfo: DataExamples.itemInfo,
                type: WinJS.UI.CellSpanningLayout
            } 
        }"
    ></div>
    

第 6 步:创建模板

最后一步是创建使用我们刚定义的 CSS 类的模板或模板函数。下面,我们将介绍如何创建 WinJS.Binding.Template 和模板函数。

JJ657974.wedge(zh-cn,WIN.10).gif方案 A:使用 WinJS.Binding.Template

  1. 在 HTML 中,定义 WinJS.Binding.Template

    <div id="myItemTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
        <div>
            <img src="#" class="regularListIconTextItem-Image" data-win-bind="src: picture" />
            <div class="regularListIconTextItem-Detail">
                <h4 data-win-bind="innerText: title"></h4>
                <h6 data-win-bind="innerText: text"></h6>
            </div>
         </div>
     </div>
    
  2. 回想我们在第 1.1 步中定义数据的方法和时间,该数据中有一个 type 属性用于指定将为每个项分配哪个 CSS 类。现在,我们即可使用该数据。在项的根元素上,将类名绑定到数据的 type 字段的值。

    <div id="myItemTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
        <div data-win-bind="className: type">
            <img src="#" class="regularListIconTextItem-Image" data-win-bind="src: picture" />
            <div class="regularListIconTextItem-Detail">
                <h4 data-win-bind="innerText: title"></h4>
                <h6 data-win-bind="innerText: text"></h6>
            </div>
        </div>
    </div>
    

    注意  在该示例中,绑定到 className,而非 class。正因如此,即使你在 HTML 中使用的是 "class",但备份 JavaScript 属性仍命名为 "className"。当应用处理 data-win-bind 属性时,会通过 JavaScript 调用分配绑定值。

    这意味着,如果 HTML 属性名称和备份 JavaScript 属性名称不同,则设置 data-win-bind 时仍应使用 JavaScript 属性。

     

  3. 通过将 ListViewitemTemplate 属性设置为模板的 ID,将其更新为使用模板。

    <div id="listView"
         data-win-control="WinJS.UI.ListView"
         data-win-options="{
             itemDataSource: DataExamples.myCellSpanningData.dataSource,
             itemTemplate: select(#'myItemTemplate'),
             layout: {
                 groupInfo: DataExamples.groupInfo,
                 itemInfo: DataExamples.itemInfo,
                 type: WinJS.UI.CellSpanningLayout
        }
    }"></div
    

如有必要,可使用模板函数代替 WinJS.Binding.Template。通过使用模板函数,你可以更灵活地确定如何生成 HTML 和分配大小。

JJ657974.wedge(zh-cn,WIN.10).gif方案 B:使用模板函数

  1. 在 JavaScript 文件中,定义模板函数。 你可以将此代码添加到包含数据的同一文件中,或者也可以将其添加到不同文件中。只需确保包含 ListView 的页面引用此文件即可。

    此示例对每个项都使用 type 数据,以为其分配用于确定其大小的 CSS 类。

    var myCellSpanningJSTemplate = function myCellSpanningJSTemplate(itemPromise) {
        return itemPromise.then(function (currentItem) {
            var result = document.createElement("div");
    
            // Use source data to decide what size to make the
            // ListView item
            result.className = currentItem.data.type;
            result.style.overflow = "hidden";
    
            // Display image
            var image = document.createElement("img");
            image.className = "regularListIconTextItem-Image";
            image.src = currentItem.data.picture;
            result.appendChild(image);
    
            var body = document.createElement("div");
            body.className = "regularListIconTextItem-Detail";
            body.style.overflow = "hidden";
            result.appendChild(body);
    
            // Display title
            var title = document.createElement("h4");
            title.innerText = currentItem.data.title;
            body.appendChild(title);
    
            // Display text
            var fulltext = document.createElement("h6");
            fulltext.innerText = currentItem.data.text;
            body.appendChild(fulltext);
    
            return result;
        });
    };
    
  2. 在函数中调用 markSupportedForProcessing,以便可通过标记进行访问。

    WinJS.Utilities.markSupportedForProcessing(myCellSpanningJSTemplate);
    
  3. 使用 WinJS.Namespace.define 使函数可公开访问。

    WinJS.Namespace.define("Templates",
        {
            myCellSpanningJSTemplate: myCellSpanningJSTemplate
        });
    
  4. 在 HTML 中,通过将 ListViewitemTemplate 属性设置为模板函数的名称,将其更新为使用模板函数。

    <div id="myListView" 
        data-win-control="WinJS.UI.ListView" 
        data-win-options="{ 
            itemDataSource: DataExamples.myCellSpanningData.dataSource,
            itemTemplate:  Templates.myCellSpanningJSTemplate
            layout: {  
                groupInfo: DataExamples.groupInfo,
                itemInfo: DataExamples.itemInfo,
                type: WinJS.UI.CellSpanningLayout
            } 
        }"
    ></div>
    

无论使用哪种模板方法,运行应用时,ListView 都将显示多种大小的项。

包含多种大小项的 ListView

备注

编辑项

若要在已启用单元格跨并功能的 ListView 中更改项,则更改时需调用 ListView.recalculateItemPosition

相关主题

ListView 项模板示例