当前位置:首页 > React

react原生实现拖拽排序

2026-01-27 17:41:30React

使用 react-dnd 实现拖拽排序

react-dnd 是一个流行的 React 拖拽库,基于 HTML5 拖拽 API 实现。安装依赖:

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

创建可拖拽项和放置区域组件:

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

const DraggableItem = ({ id, text, index, moveItem }) => {
  const [{ isDragging }, drag] = useDrag({
    type: 'ITEM',
    item: { id, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  const [, drop] = useDrop({
    accept: 'ITEM',
    hover: (draggedItem) => {
      if (draggedItem.index !== index) {
        moveItem(draggedItem.index, index);
        draggedItem.index = index;
      }
    },
  });

  return (
    <div
      ref={(node) => drag(drop(node))}
      style={{
        opacity: isDragging ? 0.5 : 1,
        padding: '8px',
        margin: '4px',
        border: '1px solid #ddd',
      }}
    >
      {text}
    </div>
  );
};

实现排序容器:

react原生实现拖拽排序

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

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

  return (
    <DndProvider backend={HTML5Backend}>
      {items.map((item, index) => (
        <DraggableItem
          key={item.id}
          id={item.id}
          text={item.text}
          index={index}
          moveItem={moveItem}
        />
      ))}
    </DndProvider>
  );
};

使用 react-beautiful-dnd 实现拖拽排序

react-beautiful-dnd 是专为列表排序优化的拖拽库。安装依赖:

npm install react-beautiful-dnd

实现可排序列表:

react原生实现拖拽排序

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

const SortableList = ({ items, setItems }) => {
  const handleDragEnd = (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={handleDragEnd}>
      <Droppable droppableId="list">
        {(provided) => (
          <div {...provided.droppableProps} ref={provided.innerRef}>
            {items.map((item, index) => (
              <Draggable key={item.id} draggableId={item.id} index={index}>
                {(provided) => (
                  <div
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                    style={{
                      padding: '8px',
                      margin: '4px',
                      border: '1px solid #ddd',
                      ...provided.draggableProps.style,
                    }}
                  >
                    {item.text}
                  </div>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
};

自定义实现拖拽排序

不依赖第三方库的基础实现:

const SortableList = ({ items, setItems }) => {
  const [draggedItem, setDraggedItem] = useState(null);

  const handleDragStart = (index) => {
    setDraggedItem(index);
  };

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

    const newItems = [...items];
    const [movedItem] = newItems.splice(draggedItem, 1);
    newItems.splice(index, 0, movedItem);
    setItems(newItems);
    setDraggedItem(index);
  };

  return (
    <div>
      {items.map((item, index) => (
        <div
          key={item.id}
          draggable
          onDragStart={() => handleDragStart(index)}
          onDragOver={() => handleDragOver(index)}
          style={{
            padding: '8px',
            margin: '4px',
            border: '1px solid #ddd',
            cursor: 'move',
          }}
        >
          {item.text}
        </div>
      ))}
    </div>
  );
};

性能优化建议

对于大型列表,应优化渲染性能:

  • 为列表项添加稳定的 key
  • 使用 React.memo 包装列表项组件
  • 避免在拖动过程中不必要的重新渲染
  • 考虑虚拟滚动技术处理超长列表

移动端适配注意事项:

  • 添加 touch 事件处理
  • 调整拖拽灵敏度
  • 考虑使用 react-dnd-touch-backend 作为后端

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

相关文章

react中monent如何获取日期

react中monent如何获取日期

使用 Moment.js 获取日期 在 React 项目中,可以通过 Moment.js 库轻松处理日期和时间。以下是几种常见的日期获取方法。 安装 Moment.js 确保项目中已安装 Mome…

react如何取消渲染

react如何取消渲染

取消渲染的方法 在React中,取消渲染通常指阻止组件在特定条件下进行不必要的渲染。可以通过以下几种方式实现: 条件渲染 使用条件语句(如if或三元运算符)直接返回null,避免渲染组件内容。例如:…

react如何保养

react如何保养

保持组件简洁 将大型组件拆分为更小、更专注的组件,每个组件只负责单一功能。避免在单个组件中处理过多逻辑或状态,这有助于提高可维护性和可测试性。 合理使用状态管理 根据应用复杂度选择状态管理方案。简…

vue实现carousel拖拽

vue实现carousel拖拽

Vue实现Carousel拖拽功能 实现一个支持拖拽的Carousel组件可以通过结合Vue的响应式特性和原生DOM事件来实现。以下是具体实现方法: 基础Carousel结构 创建一个基础的Car…

react native如何启动

react native如何启动

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

react中monent如何获取日期

react中monent如何获取日期

使用 Moment.js 获取当前日期 在 React 中通过 Moment.js 获取当前日期,可以直接调用 moment() 函数。它会返回包含当前日期和时间的 Moment 对象。 impor…