ホームページ >ウェブフロントエンド >jsチュートリアル >React dnd-kit、ソート可能なツリーリストのドラッグアンドドロップを実装
こんにちは、王富鵬です。
私はシニア フルスタック エンジニアで、17.5k のオープンソース プロジェクト PMP の作成者です。現在、Notion スタイルのナレッジ ベースを開発しています
React Nextjs と Supabase を使用した、AI の作成とコラボレーションを含む HuashuiAI。
この記事では、React と 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: [] }, ]
状態データ構造はネストされているため、最初に思いつくのは、UI 構造をネストして一緒にレンダリングすることです。
まず、
次に、下位の
ランニング効果は以下の通りです。問題は、同じレベル内ではドラッグ アンド ドロップによる並べ替えが許可されているが、レベル間の並べ替えはコンテキストではないため不可能であることです。これは合理的です
ネストは実現できないため、複数のレベルを単一のレベルに変換する必要があります。
ただし、最初に階層の深さを表示し、次にそのアイテムにどのような親ノードがあるかを知るために、各項目にancestorIds 属性を追加する必要があります。
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 }, []) } </iitem>
変換後のレンダリング効果は次のようになり、ドラッグして並べ替えることができるようになりました。ただし、状態の並べ替えが変更されるまでは有効になりません。
さらに、ancestorID の階層関係を通じて移動できるかどうかを判断することもできます。親ノードを子ノードに移動することはできません。移動しないと、ループが停止します。
たとえば、上の図で、B2 を B2a の位置にドラッグすると、B2a の先祖 ID に B2 が含まれていることがわかります。項目をその下位にドラッグできないため、これは不可能です。
操作を容易にするために、データは Zustand グローバル ストアに配置されます。
Dnd-kit は、ドラッグされた要素を activeItem として参照し、配置されたターゲットの位置を overItem として参照します。したがって、状態データを変更するということは、activeItem を overItem の位置に移動することを意味します。
単一レベルの場合、Dnd-kit は直接変更できるメソッド arrayMove を提供します。ドキュメントリンク https://docs.dndkit.com/presets/sortable
しかし、複数レベルのネストされたリスト (ツリー) では、自分で実装する必要があり、少し面倒です。コア コードはここにあります。参照用にソース コード (記事の最後にあります) をダウンロードできます。
下の図に示すように、A を B の下にドラッグすると、A は B 内ではなく、全体として B の下に移動します。
この問題を解決するには、B の後に B の子要素があるかどうかを判断する必要があります。存在する場合は、その子要素に overItem を割り当てます
次に、現在のアクティブな要素を項目の最初の要素に挿入します。
ソースコードのリンクはこちら https://github.com/wangfupeng1988/react-dnd-sortable-demo
ところで、私は国際的な仕事の機会を探しています。機会があれば、私の Github プロフィールに連絡してください。
以上がReact dnd-kit、ソート可能なツリーリストのドラッグアンドドロップを実装の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。