如何顯示大小不同的項目 (HTML)

[ 本文的目標對象是撰寫 Windows 執行階段 App 的 Windows 8.x 和 Windows Phone 8.x 開發人員。如果您正在開發適用於 Windows 10 的 App,請參閱 最新文件 ]

根據預設,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-tw,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);
    

    (根據預設,為了安全性考量,適用於 JavaScript 的 Windows Library 控制項無法存取函式與事件處理常式。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-tw,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-tw,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-tw,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 的 item-sizing 函式

除了 groupInfo 函式之外,CellSpanningLayout 也需要公開 itemInfo 函式,以判斷如何調整資料來源中不同類型的項目大小。itemInfo 函式必須傳回包含下列屬性的 JavaScript 物件:

  • width
    ListView 中個別項目的寬度

  • height
    ListView 中個別項目的高度。

JJ657974.wedge(zh-tw,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;
    });
    

    itemInfoWinJS.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-tw,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 屬性設為範本的識別碼,即可進行更新以使用範本。

    <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-tw,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 項目範本範例