当前位置:首页 > React

react实现table拖拽

2026-01-27 07:36:05React

实现React表格拖拽功能

使用react-dnd库

安装react-dnd及其HTML5后端依赖:

npm install react-dnd react-dnd-html5-backend

创建可拖拽的行组件:

import { useDrag, useDrop } from 'react-dnd';

const DraggableRow = ({ id, index, moveRow, children }) => {
  const [{ isDragging }, dragRef] = useDrag({
    type: 'ROW',
    item: { id, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  const [, dropRef] = useDrop({
    accept: 'ROW',
    hover: (draggedItem) => {
      if (draggedItem.index !== index) {
        moveRow(draggedItem.index, index);
        draggedItem.index = index;
      }
    },
  });

  return (
    <tr
      ref={(node) => dragRef(dropRef(node))}
      style={{ opacity: isDragging ? 0.5 : 1 }}
    >
      {children}
    </tr>
  );
};

在表格组件中实现拖拽逻辑

import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';

const Table = ({ data, columns }) => {
  const [items, setItems] = useState(data);

  const moveRow = (fromIndex, toIndex) => {
    const newItems = [...items];
    const [movedItem] = newItems.splice(fromIndex, 1);
    newItems.splice(toIndex, 0, movedItem);
    setItems(newItems);
  };

  return (
    <DndProvider backend={HTML5Backend}>
      <table>
        <thead>
          <tr>
            {columns.map((col) => (
              <th key={col.key}>{col.title}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {items.map((row, index) => (
            <DraggableRow
              key={row.id}
              id={row.id}
              index={index}
              moveRow={moveRow}
            >
              {columns.map((col) => (
                <td key={col.key}>{row[col.dataIndex]}</td>
              ))}
            </DraggableRow>
          ))}
        </tbody>
      </table>
    </DndProvider>
  );
};

使用react-beautiful-dnd替代方案

安装库:

react实现table拖拽

npm install react-beautiful-dnd

实现代码:

import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

const Table = ({ data, columns }) => {
  const [items, setItems] = useState(data);

  const onDragEnd = (result) => {
    if (!result.destination) return;

    const newItems = [...items];
    const [reorderedItem] = newItems.splice(result.source.index, 1);
    newItems.splice(result.destination.index, 0, reorderedItem);
    setItems(newItems);
  };

  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Droppable droppableId="table">
        {(provided) => (
          <table {...provided.droppableProps} ref={provided.innerRef}>
            <thead>
              <tr>
                {columns.map((col) => (
                  <th key={col.key}>{col.title}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {items.map((row, index) => (
                <Draggable key={row.id} draggableId={row.id} index={index}>
                  {(provided) => (
                    <tr
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                    >
                      {columns.map((col) => (
                        <td key={col.key}>{row[col.dataIndex]}</td>
                      ))}
                    </tr>
                  )}
                </Draggable>
              ))}
              {provided.placeholder}
            </tbody>
          </table>
        )}
      </Droppable>
    </DragDropContext>
  );
};

自定义实现方案

创建基础拖拽逻辑:

react实现table拖拽

const useDragAndDrop = (initialData) => {
  const [data, setData] = useState(initialData);
  const [draggedItem, setDraggedItem] = useState(null);

  const handleDragStart = (index) => {
    setDraggedItem(data[index]);
  };

  const handleDragOver = (index) => {
    if (draggedItem === null) return;

    const draggedIndex = data.findIndex(item => item.id === draggedItem.id);
    if (draggedIndex !== index) {
      const newData = [...data];
      newData.splice(draggedIndex, 1);
      newData.splice(index, 0, draggedItem);
      setData(newData);
    }
  };

  return {
    data,
    handleDragStart,
    handleDragOver,
  };
};

在组件中使用:

const Table = ({ initialData, columns }) => {
  const { data, handleDragStart, handleDragOver } = useDragAndDrop(initialData);

  return (
    <table>
      <thead>
        <tr>
          {columns.map((col) => (
            <th key={col.key}>{col.title}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {data.map((row, index) => (
          <tr
            key={row.id}
            draggable
            onDragStart={() => handleDragStart(index)}
            onDragOver={(e) => {
              e.preventDefault();
              handleDragOver(index);
            }}
          >
            {columns.map((col) => (
              <td key={col.key}>{row[col.dataIndex]}</td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  );
};

性能优化建议

对于大型表格,考虑使用虚拟滚动技术:

import { VariableSizeList as List } from 'react-window';

const Row = ({ index, style, data }) => {
  const { moveRow, items, columns } = data;

  return (
    <DraggableRow
      index={index}
      id={items[index].id}
      moveRow={moveRow}
      style={style}
    >
      {columns.map((col) => (
        <td key={col.key}>{items[index][col.dataIndex]}</td>
      ))}
    </DraggableRow>
  );
};

const VirtualizedTable = ({ data, columns }) => {
  const [items, setItems] = useState(data);
  const listRef = useRef();

  const moveRow = (fromIndex, toIndex) => {
    // ...相同的移动逻辑
    listRef.current.resetAfterIndex(Math.min(fromIndex, toIndex));
  };

  return (
    <DndProvider backend={HTML5Backend}>
      <div style={{ height: '500px', overflow: 'auto' }}>
        <List
          ref={listRef}
          height={500}
          itemCount={items.length}
          itemSize={() => 50} // 行高
          width="100%"
          itemData={{ moveRow, items, columns }}
        >
          {Row}
        </List>
      </div>
    </DndProvider>
  );
};

标签: 拖拽react
分享给朋友:

相关文章

如何评价react native

如何评价react native

React Native 的优势 跨平台开发效率高 React Native 允许开发者使用 JavaScript 和 React 编写代码,同时生成 iOS 和 Android 应用,大幅减少开发成…

react如何测试

react如何测试

React 测试方法 React 应用的测试通常涉及组件测试、集成测试和端到端测试。以下是常用的测试工具和方法: Jest Jest 是 Facebook 开发的 JavaScript 测试框架,…

vue实现图片拖拽

vue实现图片拖拽

实现图片拖拽功能 在Vue中实现图片拖拽功能可以通过HTML5的拖放API结合Vue的事件处理来完成。以下是一个完整的实现方法: 基础拖拽实现 为图片元素添加draggable属性并绑定相关事件…

vue 中实现拖拽

vue 中实现拖拽

Vue 中实现拖拽功能 使用 HTML5 原生拖拽 API HTML5 提供了原生的拖拽 API,可以通过 draggable 属性、dragstart、dragend、dragover 和 drop…

react native如何启动

react native如何启动

如何启动 React Native 项目 安装 Node.js 和 npm 确保已安装 Node.js(建议版本 16 或更高)和 npm(Node.js 自带)。可通过以下命令检查版本: nod…

react如何取消渲染

react如何取消渲染

取消渲染的方法 在React中,取消渲染通常指的是在某些条件下阻止组件渲染或中断正在进行的渲染过程。以下是几种常见的方法: 条件渲染 通过条件判断决定是否渲染组件或部分内容。可以使用if语句或三元运…