接上篇文章 Blazor 通过组件虚拟化提高性能
自适应
可以试封装成组件, 公开 itemsPerRow 和 itemsHeight 等参数, 配合查询父元素/屏幕宽度,就能自适应调节了.
在 Blazor 组件中使用 JavaScript 互操作来查询 id="div-test" 元素的渲染宽度。以下是如何实现的步骤:
- 在 wwwroot/index.html 文件中添加一个 JavaScript 函数来获取元素的宽度:
<script>window.getElementWidth = (elementId) => {const element = document.getElementById(elementId);return element ? element.offsetWidth : 0;};
</script>
- 在 Virtualized.razor 文件中使用 JSRuntime 调用这个 JavaScript 函数,并在 OnAfterRenderAsync 方法中获取元素的宽度。
@page "/"<PageTitle>Virtualized Orders</PageTitle><h1>Virtualized Orders</h1><div id="div-test" style="height: 370px; overflow-y: scroll; width: 380px; "><Virtualize Items="GroupedOrders" Context="orderGroup" ItemSize="16.667f"><div style="display: flex; flex-direction: row; flex-wrap: wrap; ">@foreach (var order in orderGroup){<div style="width: 100px; height: 100px; background-color: cadetblue; padding: 10px; margin: 10px;"><div>$ @order.Value</div></div>}</div></Virtualize>
</div><p>元素宽度: @elementWidth px</p>@code {private int elementWidth;int itemsPerRow = 3;public record Order(Guid Id, int Value);public IList<Order> Orders { get; set; } = new List<Order>();public IList<IEnumerable<Order>>? GroupedOrders { get; set; }[Inject]private IJSRuntime JSRuntime { get; set; }protected override async Task OnAfterRenderAsync(bool firstRender){if (firstRender){elementWidth = await JSRuntime.InvokeAsync<int>("getElementWidth", "div-test");StateHasChanged();}}protected override void OnInitialized(){var random = new Random();for (int i = 0; i < 100; i++){Orders.Add(new Order(Guid.NewGuid(), random.Next(20, 9999)));}GroupedOrders = Orders.Select((order, index) => new { order, index }).GroupBy(x => x.index / itemsPerRow).Select(g => g.Select(x => x.order)).ToList();}
}
加入自动计算
@page "/"<PageTitle>Virtualized Orders</PageTitle><h1>Virtualized Orders</h1><div id="div-test" style="height: 370px; overflow-y: scroll; width: 90vw; "><Virtualize Items="GroupedOrders" Context="orderGroup"><div style="display: flex; flex-direction: row; flex-wrap: wrap; ">@foreach (var order in orderGroup){<div style="width: 100px; height: 100px; background-color: cadetblue; padding: 10px; margin: 10px;"><div>$ @order.Value</div></div>}</div></Virtualize>
</div>@code {private int elementWidth;int itemsPerRow = 3;int itemsHeight = 100; public record Order(Guid Id, int Value);public IList<Order> Orders { get; set; } = new List<Order>();public IList<IEnumerable<Order>>? GroupedOrders { get; set; }[Inject][System.Diagnostics.CodeAnalysis.NotNull]private IJSRuntime? JSRuntime { get; set; }protected override async Task OnAfterRenderAsync(bool firstRender){if (firstRender){elementWidth = await JSRuntime.InvokeAsync<int>("getElementWidth", "div-test");itemsPerRow = elementWidth / (itemsHeight+20);StateHasChanged();}}protected override void OnInitialized(){var random = new Random();for (int i = 0; i < 100; i++){Orders.Add(new Order(Guid.NewGuid(), random.Next(20, 9999)));}GroupedOrders = Orders.Select((order, index) => new { order, index }).GroupBy(x => x.index / itemsPerRow).Select(g => g.Select(x => x.order)).ToList();}
}