首页 > web前端 > js教程 > React dnd-kit,实现树列表拖放排序

React dnd-kit,实现树列表拖放排序

Susan Sarandon
发布: 2024-12-10 20:09:10
原创
582 人浏览过

大家好,我是王福鹏。

我是一名高级全栈工程师,也是 17.5k 开源项目 PMP 的作者。现在我正在开发一个Notion风格的知识库
HuashuiAI 包括 AI 写作和协作,使用 React Nextjs 和 Supabase。

在这篇文章中,我将分享如何通过 React 和 dnd-kit 实现树列表拖放排序。源码链接在本文底部。

React   dnd-kit, implement tree-list drag and drop sortable

Dnd-kit 和可排序组件

Dnd-kit 是 React 生态中常见的拖放工具,默认支持排序。

    <DndContext 
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragEnd={handleDragEnd}
    >
      <SortableContext 
        items={items}
        strategy={verticalListSortingStrategy}
      >
        {items.map(id => <SortableItem key={id}>



<p>But it can only support the one-level list. If we want to implement a multi-level nested list (or tree), we have to customize it.</p>

<h2>
  
  
  Define state date structure
</h2>

<p>Modern front-end frameworks such as React Vue are data-driven views, so defining data structures first and then considering UI rendering.</p>

<p>The most common data structure definition for multi-level nested lists (trees) is as follows, and virtual DOM vnode is also defined in this way.<br>
</p>

<pre class="brush:php;toolbar:false">const defaultItems = [
  { id: 'A', children: [] },
  {
    id: 'B',
    children: [
      { id: 'B1', children: [] },
      {
        id: 'B2',
        children: [
          { id: 'B2a', children: [] },
          { id: 'B2b', children: [] },
        ],
      },
    ],
  },
  { id: 'C', children: [] },
  {
    id: 'D',
    children: [
      { id: 'D1', children: [] },
      { id: 'D2', children: [] },
    ],
  },
  { id: 'E', children: [] },
]
登录后复制

多级嵌套SortableContext不可行

因为状态数据结构是嵌套的,所以我首先想到的就是嵌套并一起渲染UI结构。

首先,嵌套 ;在 内,这与单层列表使用的方法相同。

React   dnd-kit, implement tree-list drag and drop sortable

然后,继续嵌套下级 中展示孩子们。

React   dnd-kit, implement tree-list drag and drop sortable

运行效果如下。问题是同一级别内允许拖放排序,但跨级别排序是不可能的,因为它不是上下文 - 这是合理的

React   dnd-kit, implement tree-list drag and drop sortable

多级转换为单级是可行的

由于嵌套不可行,因此需要将多级转换为单级。

但是需要为每个item添加祖先Ids属性,首先是为了显示层次结构的深度,其次是为了知道它有哪些父节点。

interface IItem {
  id: string
  ancestorIds?: string[]
  children?: IItem[]
}

function flatten(items: IItem[]): IItem[] {
  return items.reduce<IItem[]>((acc, item) => {
    acc.push(item)
    if (item.children) {
      const children = item.children.map((i) => ({
        ...i,
        ancestorIds: [...(item.ancestorIds || []), item.id], // add ancestorIds
      }))
      acc.push(...flatten(children))
    }
    return acc
  }, [])
}
登录后复制

转换后的渲染效果如下,现在可以拖动排序了。不过要修改状态排序后才会生效。

React   dnd-kit, implement tree-list drag and drop sortable

此外,我们还可以通过祖先ID的层级关系来判断是否可以移动。父节点不能移动到子节点,否则循环会死。

例如上图中,如果我们要将B2拖到B2a的位置,我们会发现B2a的祖先ID包含B2。这是不可能的,因为您无法将项目拖动到其自己的下属项目。

修改状态数据

为了方便操作,数据放置在Zustand全局存储中。

React   dnd-kit, implement tree-list drag and drop sortable

Dnd-kit 将拖动的元素称为 activeItem,将放置的目标位置称为 overItem。所以修改状态数据意味着将activeItem移动到overItem的位置。

如果是单关,Dnd-kit提供了一个方法arrayMove,可以直接修改。文档链接 https://docs.dndkit.com/presets/sortable

React   dnd-kit, implement tree-list drag and drop sortable

但是在多级嵌套列表(树)中,需要自己实现,有点麻烦。核心代码在这里,大家可以下载源码(文末)参考。

React   dnd-kit, implement tree-list drag and drop sortable

遇到问题

如下图所示,将A拖到B下面时,A会整体移动到B的底部,而不是在B内部。

React   dnd-kit, implement tree-list drag and drop sortable

要解决这个问题,需要判断B之后是否还有B的子元素,如果有,则将overItem赋值给其子元素

React   dnd-kit, implement tree-list drag and drop sortable

然后将当前活动元素插入到items的第一个元素中。

React   dnd-kit, implement tree-list drag and drop sortable

结束

源代码链接在这里 https://github.com/wangfupeng1988/react-dnd-sortable-demo

顺便说一句,我正在寻找一份国际工作机会,如果你有机会,欢迎通过我的 Github 个人资料联系我。

以上是React dnd-kit,实现树列表拖放排序的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板