首頁 > 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
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板