当前位置:首页 > 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

如何手写一个react

手写一个简单的 React 创建一个基础的 React 实现需要理解其核心概念:虚拟 DOM、组件、状态管理和渲染。以下是一个简化版的 React 实现。 创建虚拟 DOM 虚拟 DOM 是真实 D…

如何选购react

如何选购react

选购 React 相关产品或服务的建议 React 是一个用于构建用户界面的 JavaScript 库,广泛应用于前端开发。以下是选购 React 相关产品(如课程、书籍、工具、组件库等)的参考方法:…

如何创建react

如何创建react

创建React项目的步骤 使用Create React App工具快速搭建React项目。确保已安装Node.js(版本需≥14.0.0)和npm(版本需≥5.6)。 打开终端或命令行工具,运行以下…

react如何获取路由

react如何获取路由

获取当前路由路径 在React中获取当前路由路径可以通过react-router-dom提供的useLocation钩子。useLocation返回一个包含当前路由信息的对象,其中pathname属性…

react 如何引用slider

react 如何引用slider

使用 React 实现 Slider 组件 在 React 中实现 Slider 功能可以通过原生 HTML 的 <input type="range"> 或第三方库(如 react-sl…

react如何取消监听

react如何取消监听

取消事件监听的方法 在React中取消事件监听通常涉及在组件卸载时移除之前添加的监听器。以下是几种常见场景的解决方案: 类组件中的取消监听 对于类组件,通常在componentDidMount中添加…