前言

今日介紹另一個特別的內建元件 Virtualize 元件虛擬化,這個效果很類似 Lazy load,只渲染使用者看得見的部分

基本使用

以下的程式碼一次性會產出5000個 div 標籤

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@page "/VirtualizeExample"
<div style="height:500px;overflow-y:scroll">
    @foreach (var content in contentList)
    {
        <div class="alert alert-primary" role="alert">
            @content
        </div>
    }
</div>

@code {
    private List<int> contentList = Enumerable.Range(0, 5000).ToList();
}

改寫成 Virtualize

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@page "/VirtualizeExample"
<div style="height:500px;overflow-y:scroll">
    <Virtualize Items="contentList">
        <div class="alert alert-primary" role="alert">
            @context
        </div>
    </Virtualize>
</div>

@code {
    private List<int> contentList = Enumerable.Range(0, 5000).ToList();
}

效果一樣,但是實際上是在捲動時渲染

指定資料來源

若不想要將資料一次載入記憶體內,而想從外部提供資料我們可以設定 ItemsProviderProvider 會接收到ItemsProviderRequest ,告知需要跳過幾筆資料提供幾筆資料以及資料的總數,就像做分頁一樣,以下是實作 ItemsProvider 的部分

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@page "/VirtualizeExample"
<div style="height:500px;overflow-y:scroll">
    <Virtualize ItemsProvider="@LoadData">
        <div class="alert alert-primary" role="alert">
            @context
        </div>
    </Virtualize>
</div>

@code {
    private List<int> contentList = Enumerable.Range(0, 5000).ToList();

    private async ValueTask<ItemsProviderResult<int>> LoadData(ItemsProviderRequest request)
    {
        Console.WriteLine($"跳過 {request.StartIndex} 取得{request.Count}");
        return new ItemsProviderResult<int>(contentList.Skip(request.StartIndex).Take(request.Count), contentList.Count);
    }
}

可以在右邊的 Console 上看到,當我往下捲動 Blazor 也不斷的在幫我取得資料

預留框架

如果資料是遠端來源,可能需要一點時間才能取得 Blazor 也有提供預留資料位置的方法,分別是 ItemContentPlaceholder

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@page "/VirtualizeExample"
<div style="height:500px;overflow-y:scroll">
    <Virtualize ItemsProvider="@LoadData">
        <ItemContent>
            <div class="alert alert-primary" role="alert">
                @context
            </div>
        </ItemContent>
        <Placeholder>
            <div class="alert alert-primary" role="alert">
                載入中
            </div>
        </Placeholder>
    </Virtualize>
</div>

@code {
    private List<int> contentList = Enumerable.Range(0, 5000).ToList();

    private async ValueTask<ItemsProviderResult<int>> LoadData(ItemsProviderRequest request)
    {
        await Task.Delay(TimeSpan.FromSeconds(1));
        Console.WriteLine($"跳過 {request.StartIndex} 取得{request.Count}");
        return new ItemsProviderResult<int>(contentList.Skip(request.StartIndex).Take(request.Count), contentList.Count);
    }
}

小結

以上是元件虛擬化的一些基本用法說明,明天會繼續完成內建元件的介紹