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

调用StateHasChanged后Blazor有序列表仍未更新问题

Blazor集成Sortable.js排序失效问题解决方案

问题核心

Sortable.js拖拽后已直接修改DOM结构,导致Blazor虚拟DOM与实际DOM不一致;同时OnSort方法未正确更新Item的OrderIndex属性,仅重新排序集合无法触发Blazor的变更检测,最终DOM列表未同步更新。

具体修复步骤

1. 阻止Sortable.js修改DOM,由Blazor全权控制渲染

修改JS初始化代码,在拖拽结束后先还原Sortable移动的DOM元素,避免与Blazor渲染冲突:

window.initializeSortable = (container, blazorComponent, items, options) => {
  const common = {
    onEnd: async function (evt) {
      // 还原Sortable移动的DOM,保证Blazor渲染时DOM初始状态正确
      evt.item.parentNode.insertBefore(evt.item, evt.oldIndex >= evt.newIndex ? evt.futureIndex : evt.futureIndex.nextSibling);
      // 调用Blazor方法处理排序逻辑
      await blazorComponent.invokeMethodAsync('UpdateItemOrder', evt.oldIndex, evt.newIndex);
    },
  };
  const init = Object.assign({}, { animation: 150 }, options, common);
  if (container != null) {
    Sortable.create(container, init);
    container.__blazor_component = blazorComponent;
  }
};

// 添加销毁Sortable的方法(用于组件参数变更时重置)
window.destroySortable = (container) => {
  if (container?.sortable) {
    container.sortable.destroy();
  }
};

2. 正确更新Item的OrderIndex值

修改OnSort方法,根据拖拽的索引变更实际调整每个Item的OrderIndex,并更新集合引用触发Blazor检测:

public async Task OnSort(SortChangedArgs sortChangedArgs)
{
    var oldIndex = sortChangedArgs.OldIndex;
    var newIndex = sortChangedArgs.NewIndex;

    var items = ViewModel.VerificationItems.ToList();
    var movedItem = items[oldIndex];

    // 调整项在集合中的位置
    items.RemoveAt(oldIndex);
    items.Insert(newIndex, movedItem);

    // 更新所有项的OrderIndex为当前索引
    for (int i = 0; i < items.Count; i++)
    {
        items[i].OrderIndex = i;
    }

    // 更新ViewModel集合(引用变更触发Blazor变更检测)
    ViewModel.VerificationItems = items;

    StateHasChanged();
}

3. 让组件感知Items参数变化

修改BlazorSortable组件,在参数变更时重置Sortable,确保绑定最新DOM:

private DotNetObjectReference<BlazorSortable>? _dotNetRef;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        _dotNetRef = DotNetObjectReference.Create(this);
        await InitializeSortableInJavascript();
    }
}

protected override async Task OnParametersSetAsync()
{
    await base.OnParametersSetAsync();
    // 非首次渲染时,若Items变更则重置Sortable
    if (!firstRender)
    {
        await JSRuntime.InvokeVoidAsync("destroySortable", _dropZoneContainer);
        await InitializeSortableInJavascript();
    }
}

public async ValueTask DisposeAsync()
{
    _dotNetRef?.Dispose();
    await JSRuntime.InvokeVoidAsync("destroySortable", _dropZoneContainer);
}

public async Task InitializeSortableInJavascript()
{
    await JSRuntime.InvokeVoidAsync("initializeSortable", _dropZoneContainer, _dotNetRef, Items, Options);
}

4. 移除不必要的延迟

删除OnAfterRenderAsync中的Task.Delay(100),Blazor的OnAfterRenderAsync已保证DOM渲染完成,可直接初始化Sortable。

内容的提问来源于stack exchange,提问作者Vlado Pandžić

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 02:02:19