Blazor 通过拖放重新排序列表

Pau*_*ley 3 blazor blazor-server-side

我正在学习来自 WinForm UWP 背景的 Blazor。我有一个游戏列表:

public class Game
{
    public string ID { get; set; }
    public string Text { get; set; }
    public override string ToString()
    {
        return Text;
    }
}
List<Game> Games = new List<Game> {
new Game() { ID= "Game1", Text= "American Football"},
new Game() { ID= "Game2", Text= "Badminton"  },
new Game() { ID= "Game3", Text= "Basketball"  },
new Game() { ID= "Game4", Text= "Cricket"},
new Game() {  ID= "Game5", Text= "Football" },
new Game() { ID= "Game6", Text= "Golf"  },
new Game() { ID= "Game7", Text= "Hockey"  },
new Game() { ID= "Game8", Text= "Rugby" },
new Game() { ID= "Game9", Text= "Snooker"  },
new Game() { ID= "Game10", Text= "Tennis" },
Run Code Online (Sandbox Code Playgroud)

}; 我想拖放以重新排序我的列表。这是我的元素。

<ul ondragover="event.preventDefault();" style="margin:20px">
@foreach (var item in Games)
{
    <li draggable="true" style="list-style-type:none; height:30px" @key="item" tabindex="1"
        @onclick="@(()=> ClickItem(item))" @ondrop="@(()=> Drop(item))">
        <span>@item.Text</span>
    </li>
}
Run Code Online (Sandbox Code Playgroud)

我使用@onclick 在列表中选择一个项目:

Game currentGame;
int currentIndex;
void ClickItem(Game item)
{
    currentIndex = Games.FindIndex(a => a.Text == item.Text);
    currentGame = item;
}
Run Code Online (Sandbox Code Playgroud)

我处理ondrop:

    void Drop(Game item)
{
    var newIndex = Games.FindIndex(a => a.Text == item.Text);
    Games.Insert(newIndex, currentGame);
    Games.RemoveAt(currentIndex);
    StateHasChanged();
}
Run Code Online (Sandbox Code Playgroud)

Drop 方法中没有任何事情发生,列表不会更改,应用程序中断但不会引发错误并且导航停止。所有事件都在触发。找不到任何帮助的例子。

Ala*_*bra 16

您只能在 Blazor 中执行此操作 - 不需要外部 js 库:

在 Blazor 中拖放

<ul ondragover="event.preventDefault();"
    ondragstart="event.dataTransfer.setData('', event.target.id);">
    @foreach (var item in Models.OrderBy(x => x.Order))
    {
        <li @ondrop="()=>HandleDrop(item)" @key="item">
            <div @ondragleave="@(()=> {item.IsDragOver = false;})"
                @ondragenter="@(()=>{item.IsDragOver = true;})"
                style="@(item.IsDragOver?"border-style: solid none none none; border-color:red;":"")"
                @ondragstart="() => draggingModel = item"
                @ondragend="()=> draggingModel = null" draggable="true">@item.Name</div>
        </li>
    }
</ul>

@code
{
    public List<Model> Models { get; set; } = new();

    public class Model
    {
        public int Order { get; set; }
        public string Name { get; set; } = "";
        public bool IsDragOver{ get; set; } 
    }

    protected override void OnInitialized()
    {//fill names with "random" string
        for (var i = 0; i < 10; i++)
        {
            Model m = new() { Order = i, Name = $"Item {i}" };
            Models.Add(m);
        }
        base.OnInitialized();
    }

    private void HandleDrop(Model landingModel)
    {//landing model -> where the drop happened
        if (draggingModel is null) return;
        int originalOrderLanding = landingModel.Order;//keep the original order for later
        //increase model under landing one by 1
        Models.Where(x => x.Order >= landingModel.Order).ToList().ForEach(x => x.Order++);
        draggingModel.Order = originalOrderLanding;//replace landing model
        int ii = 0;
        foreach (var model in Models.OrderBy(x=>x.Order).ToList())
        {
            model.Order = ii++;//keep the numbers from 0 to size-1
            model.IsDragOver = false;//remove drag over. 
        }
    }

    private Model? draggingModel;//the model that is being dragged
}
Run Code Online (Sandbox Code Playgroud)

完整的项目可以在我的GitHub 存储库中找到。

编辑:.NET 8 更新刚刚到来。还提供作为最后一项订购的解决方案。


Qua*_*ngo 10

我设法在 BlazorFiddle 中为您创建了一个工作示例:

https://blazorfiddle.com/s/8jurefka

根据 Henk 的建议,我用处理事件ClickItemStartDrag方法替换了你的@ondrag。如果您使用,@onclick您必须先单击一个项目,然后才能拖动它。使用@ondrag事件可以避免这种情况。我认为这可能是某些情况下出现问题的原因。

我还添加了一些调试助手,以便我可以看到发生了什么。

  • 警告 !如果您使用服务器端 blazor,ondrag 是一个性能杀手(但如果您确实需要收到任何鼠标移动通知,那就去吧)。请改用 @ondragstart 事件。根据解决方案,类似的内容: &lt;div ondragover="event.preventDefault();"&gt; @ foreach (var item in Data) { &lt;div style="width: 100%;border:1px Solid black"draggable=" true" @ ondragstart="@ (()=&gt; StartDrag(item))" @ondrop="@(() =&gt;DropOn(item))"&gt; @Template?.Invoke(item) &lt;/div&gt; } &lt;/分区&gt; (6认同)
  • 很棒的演示(+1)。然而,当应用于我的 Blazor wasm 应用程序时,我注意到在重新排序大型列表时出现了巨大的延迟。解决方法是将 @ondrag="@(()=&gt; StartDrag(item))" 更改为 @ondragstart="@(()=&gt; StartDrag(item))"。这次改变之后,速度非常快。 (3认同)