You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React TanStack Table组件中实现多行拖拽重排序功能

如何在React TanStack Table组件中实现多行拖拽重排序功能

我完全懂你的痛点——用户选中一堆行后,拖拽时没有直观的UI提示,根本不知道自己正在移动多少行,体验确实不够顺畅。结合你提到的UX设计思路,咱们可以从添加拖拽幽灵提示UI和完善多行拖拽逻辑细节这两部分入手,把这个功能做的更友好。

第一步:添加拖拽时的幽灵提示组件

先做那个能显示选中行数的侧边提示,让用户拖拽时一眼就能明确自己在移动多少行。新增一个DragGhost组件:

// 拖拽时的幽灵提示组件
function DragGhost({ selectedCount }) {
  return (
    <div className={styles.dragGhost}>
      <span>{selectedCount} 行已选中,正在拖拽重排</span>
    </div>
  );
}

接着在Table组件里添加状态,跟踪拖拽激活状态和选中行数,同时监听拖拽开始事件:

// 在Table组件内新增状态
const [isDragging, setIsDragging] = useState(false);
const [draggingSelectedCount, setDraggingSelectedCount] = useState(0);

// 监听拖拽开始事件,更新状态
const handleDragStart = (event) => {
  const selectedRowIds = Object.keys(rowSelection).filter(id => rowSelection[id]);
  setDraggingSelectedCount(selectedRowIds.length);
  setIsDragging(true);
};

// 修改原有的handleDragEnd,添加拖拽结束后的状态重置
const handleDragEnd = (event) => {
  setIsDragging(false);
  // ... 保留原来的拖拽结束逻辑
};

最后在渲染时,把幽灵提示放在表格左侧合适的位置:

return (
  <div className={styles.tableContainer}>
    {/* 拖拽幽灵提示:仅在拖拽多行时显示 */}
    {isDragging && draggingSelectedCount > 1 && (
      <DragGhost selectedCount={draggingSelectedCount} />
    )}
    {/* 原有的搜索框、表格、分页等内容 */}
    <input 
      type="text"
      value={globalFilter}
      onChange={(e) => setGlobalFilter(e.target.value)}
      placeholder="Search..."
      className={styles.search}
    />
    <DndContext 
      collisionDetection={closestCenter} 
      onDragStart={handleDragStart} // 绑定拖拽开始事件
      onDragEnd={handleDragEnd}
    >
      {/* ... 原有的表格内容 */}
    </DndContext>
  </div>
);

第二步:完善多行拖拽的逻辑细节

现在的拖拽逻辑已经能移动多行,但还需要优化插入位置的准确性,确保选中组能精准落在用户预期的位置:

const handleDragEnd = (event) => {
  const { active, over } = event;
  setIsDragging(false);

  if (!active || !over || active.id === over.id) return;

  const selectedRowIds = Object.keys(rowSelection).filter(id => rowSelection[id]);
  const hasSelectedRows = selectedRowIds.length > 0;

  if (hasSelectedRows) {
    // 拆分选中行和未选中行
    const selectedRows = data.filter(item => selectedRowIds.includes(item.id));
    const otherRows = data.filter(item => !selectedRowIds.includes(item.id));

    // 计算插入位置:处理拖拽方向,确保插入位置符合用户预期
    const originalActiveIndex = data.findIndex(item => item.id === active.id);
    const originalOverIndex = data.findIndex(item => item.id === over.id);
    const overIndexInOther = otherRows.findIndex(item => item.id === over.id);
    
    const insertIndex = originalActiveIndex < originalOverIndex
      ? overIndexInOther
      : overIndexInOther + 1;

    // 重组数据数组
    const newData = [
      ...otherRows.slice(0, insertIndex),
      ...selectedRows,
      ...otherRows.slice(insertIndex)
    ];

    setData(newData);
    // 保持选中状态(可选,根据需求调整是否保留选中)
    setRowSelection(prev => {
      const newSelection = {};
      selectedRowIds.forEach(id => newSelection[id] = true);
      return newSelection;
    });
  } else {
    // 单行拖拽逻辑保持不变
    const oldIndex = data.findIndex(item => item.id === active.id);
    const newIndex = data.findIndex(item => item.id === over.id);
    if (oldIndex !== -1 && newIndex !== -1) {
      const newData = arrayMove([...data], oldIndex, newIndex);
      setData(newData);
    }
  }
};

第三步:补充样式(Table.module.css)

给幽灵提示和选中行添加样式,让视觉效果更贴合UX设计:

.tableContainer {
  position: relative;
  margin-left: 130px; /* 给左侧幽灵提示留出空间 */
}

.dragGhost {
  position: absolute;
  left: -120px;
  top: 50%;
  transform: translateY(-50%);
  background: #2196F3;
  color: white;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 14px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
  z-index: 100;
}

.row {
  transition: background-color 0.2s ease;
}

.row:hover {
  background-color: #f5f5f5;
}

.dragHandle {
  cursor: grab;
  border: none;
  background: transparent;
  padding: 4px;
}

.dragHandle:active {
  cursor: grabbing;
}

第四步:优化Row组件的选中样式

让选中行的高亮更明显,修改Row组件内的样式判断:

const style = {
  transform: CSS.Transform.toString(transform),
  transition,
  backgroundColor: isSelected ? "#e0f7fa" : "inherit",
};

这样调整后,用户选中多行拖拽时,左侧会弹出提示显示选中行数,同时拖拽逻辑能精准把整个选中组移动到目标位置,体验就和你参考的UX设计一致了。

备注:内容来源于stack exchange,提问作者Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:23:05