mcpField
D
dnd-kit-implementation

dnd-kit-implementation

github.com/atman-33开发92 次安装
代码仓库

关于 dnd-kit-implementation

dnd-kit-implementation 是使用 dnd-kit 实现拖放交互的开发技能,面向构建可排序容器和可放置目标的开发者。它通过拖动上下文切换容器行为,并给出状态更新模式。

主要功能

  1. 01组合可排序与可放置行为
  2. 02根据拖动上下文切换逻辑
  3. 03通过 ID 前缀区分容器与项目
  4. 04使用不可变状态更新

适用场景

  1. 01重排看板列并移动卡片
  2. 02整理文件夹并移动文件
  3. 03调整播放列表及歌曲顺序
  4. 04重排任务列表并移动任务

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/atman-33/skills --skill dnd-kit-implementation

安装后在 Claude Code 中输入/dnd-kit-implementation确认已加载。

附带文件references/implementation-patterns.mdreferences/state-management.md

详细介绍

dnd-kit 实现指南

概述

此技能提供了使用 dnd-kit 库实现拖放功能的模式,可同时支持可排序容器和可放置目标。

核心概念

组合使用 useSortable 和 useDroppable 的关键在于基于拖动上下文的条件逻辑:

  • 拖动项目时 → 容器仅作为放置目标
  • 拖动容器时 → 容器作为可排序元素

实现方式是检测当前正在拖动的对象,并仅启用相应的功能。

实现模式

容器组件结构
const SortableDroppableContainer = ({ container }) => {
  // useSortable for container reordering
  const {
    attributes,
    listeners,
    setNodeRef: setSortableRef,
    transform,
    transition,
    isDragging,
  } = useSortable({ id: container.id });

  // useDroppable for receiving items
  const { setNodeRef: setDroppableRef, isOver } = useDroppable({
    id: container.id,
  });

  // Active element from context
  const { active } = useDndContext();

  // Determine behavior based on what's being dragged
  const isItem = active?.id?.toString().startsWith('item-');
  const isContainer = active?.id?.toString().startsWith('container-');

  // Apply conditional refs
  const setNodeRef = isItem ? setDroppableRef : setSortableRef;

  return (
    <div ref={setNodeRef} {...(isContainer ? attributes : {})} style={style}>
      <div {...(isContainer ? listeners : {})}>{/* Drag handle */}</div>
      {/* Container content */}
    </div>
  );
};
关键实现要点
  1. 双钩子用法:在同一组件中同时使用 useSortable 和 useDroppable
  2. 上下文检测:使用 useDndContext() 检查当前正在拖动的对象
  3. 条件引用:根据拖动状态应用相应的 ref
  4. ID 命名约定:使用 container-* 和 item-* 等前缀区分类型
ID 命名约定
// Containers
const containerId = `container-${id}`;

// Items
const itemId = `item-${id}`;

这一约定使条件逻辑清晰且易于维护。

状态管理关键点

更新容器项目时,始终创建新对象:

// ❌ Won't trigger re-render
containers.items.push(newItem);

// ✅ Correct - creates new reference
setContainers(prev => prev.map(c =>
  c.id === targetId
    ? { ...c, items: [...c.items, newItem] }
    : c
));

常见用例

  • 看板:重新排列列,并在列之间移动卡片
  • 文件管理:重新整理文件夹,并将文件移入文件夹
  • 播放列表编辑器:重新排列播放列表,并向播放列表添加歌曲
  • 任务管理器:重新排列任务列表,并在列表之间移动任务

参考资料

如需详细的实现示例和代码模式,请参阅:

评论

支持 Markdown