You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Virtualize组件渲染完成后触发JS方法的实现方案

解决方案:监听Blazor Virtualize渲染完成并初始化Popover

核心思路

利用Virtualize组件的ItemsProvider回调标记新数据加载完成,结合OnAfterRenderAsync在DOM更新后触发JS初始化逻辑,同时通过自定义属性避免重复绑定Popover。


步骤1:组件代码实现

@inject IJSRuntime JSRuntime

<table class="table">
    <thead>
        <tr>
            <th>ID</th>
            <th>内容</th>
        </tr>
    </thead>
    <tbody>
        <Virtualize ItemsProvider="LoadItems" Context="item">
            <tr>
                <td>@item.Id</td>
                <td>
                    <!-- 给需要Popover的元素加未初始化标记 -->
                    <span class="text-primary" 
                          data-bs-toggle="popover" 
                          data-bs-content="@item.Detail" 
                          data-popover-initialized="false">
                        @item.Name
                    </span>
                </td>
            </tr>
        </Virtualize>
    </tbody>
</table>

@code {
    // 标记是否需要重新初始化Popover
    private bool _needsPopoverSetup;

    // Virtualize的数据加载回调
    private async ValueTask<ItemsProviderResult<MyDataItem>> LoadItems(ItemsProviderRequest request)
    {
        // 替换为你的实际数据加载逻辑
        var items = await FetchPaginatedData(request.StartIndex, request.Count);
        var totalCount = await GetTotalItemCount();

        // 新数据加载完成,标记需要初始化Popover
        _needsPopoverSetup = true;
        StateHasChanged();

        return new ItemsProviderResult<MyDataItem>(items, totalCount);
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // 首次渲染或新数据加载后,执行Popover初始化
        if (firstRender || _needsPopoverSetup)
        {
            await JSRuntime.InvokeVoidAsync("setupPopovers");
            _needsPopoverSetup = false;
        }
    }

    // 以下为模拟数据方法,请替换为实际业务逻辑
    private async Task<List<MyDataItem>> FetchPaginatedData(int startIndex, int count)
    {
        await Task.Delay(100);
        return Enumerable.Range(startIndex, count)
            .Select(i => new MyDataItem 
            { 
                Id = i, 
                Name = $"条目{i}", 
                Detail = $"条目{i}的详细描述内容" 
            })
            .ToList();
    }

    private async Task<int> GetTotalItemCount()
    {
        await Task.Delay(100);
        return 150;
    }

    public class MyDataItem
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Detail { get; set; }
    }
}

步骤2:JS初始化逻辑

在wwwroot/js目录下创建popover-utils.js,并在_Layout.cshtml中引入:

window.setupPopovers = function() {
    // 只选择未初始化的Popover元素,避免重复绑定
    const uninitializedElements = document.querySelectorAll('[data-bs-toggle="popover"][data-popover-initialized="false"]');
    
    uninitializedElements.forEach(el => {
        // 用Popper.js创建Bootstrap风格的Popover
        new bootstrap.Popover(el, {
            trigger: 'hover',
            placement: 'top',
            html: false
        });
        
        // 标记为已初始化
        el.setAttribute('data-popover-initialized', 'true');
    });
}

关键说明

  1. 触发时机:Virtualize每次滚动加载新数据时,ItemsProvider会被调用,此时标记_needsPopoverSetup并触发状态变更,确保组件重新渲染后执行OnAfterRenderAsync。
  2. 性能优化:通过data-popover-initialized属性过滤已初始化元素,避免重复创建Popover实例。
  3. 兼容性:适配Bootstrap 5 CSS和Popper.js的原生API,无需引入第三方Blazor库。

内容的提问来源于stack exchange,提问作者Grandizer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 11:25:29