当前位置:首页 > React

用react实现拖拽

2026-01-27 07:31:26React

实现拖拽功能的基本步骤

安装依赖库react-dnd

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

创建可拖拽组件

import { useDrag } from 'react-dnd';

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

  return (
    <div
      ref={drag}
      style={{
        opacity: isDragging ? 0.5 : 1,
        cursor: 'move',
        padding: '8px',
        margin: '4px',
        backgroundColor: 'lightblue',
      }}
    >
      {text}
    </div>
  );
}

创建放置区域组件

import { useDrop } from 'react-dnd';

function DropZone({ onDrop }) {
  const [{ isOver }, drop] = useDrop(() => ({
    accept: 'ITEM',
    drop: (item) => onDrop(item.id),
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
    }),
  }));

  return (
    <div
      ref={drop}
      style={{
        minHeight: '200px',
        border: isOver ? '2px dashed red' : '2px dashed gray',
        padding: '16px',
        margin: '16px',
      }}
    >
      放置区域
    </div>
  );
}

组合组件实现完整功能

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

function App() {
  const [items, setItems] = useState([
    { id: 1, text: '项目1' },
    { id: 2, text: '项目2' },
    { id: 3, text: '项目3' },
  ]);

  const handleDrop = (id) => {
    console.log(`项目${id}被放置`);
  };

  return (
    <DndProvider backend={HTML5Backend}>
      <div>
        {items.map((item) => (
          <DraggableItem key={item.id} id={item.id} text={item.text} />
        ))}
        <DropZone onDrop={handleDrop} />
      </div>
    </DndProvider>
  );
}

自定义拖拽手柄实现

仅允许特定元素触发拖拽

用react实现拖拽

function DraggableWithHandle({ id, text }) {
  const [{ isDragging }, drag, dragPreview] = useDrag(() => ({
    type: 'ITEM',
    item: { id },
  }));

  return (
    <div ref={dragPreview} style={{ opacity: isDragging ? 0.5 : 1 }}>
      <div ref={drag} style={{ cursor: 'move', padding: '4px' }}>
        🖐️ 拖拽手柄
      </div>
      <div style={{ padding: '8px', backgroundColor: 'lightgreen' }}>
        {text}
      </div>
    </div>
  );
}

拖拽排序实现

列表项拖拽排序逻辑

const moveItem = (dragIndex, hoverIndex) => {
  setItems((prevItems) => {
    const newItems = [...prevItems];
    const [removed] = newItems.splice(dragIndex, 1);
    newItems.splice(hoverIndex, 0, removed);
    return newItems;
  });
};

// 在DropZone组件中使用hover回调
const [, drop] = useDrop({
  accept: 'ITEM',
  hover(item, monitor) {
    if (!ref.current) return;
    const dragIndex = item.index;
    const hoverIndex = index;
    if (dragIndex === hoverIndex) return;
    moveItem(dragIndex, hoverIndex);
    item.index = hoverIndex;
  },
});

触摸设备支持

安装触摸后端

npm install react-dnd-touch-backend

配置触摸后端

用react实现拖拽

import { TouchBackend } from 'react-dnd-touch-backend';

// 在应用中使用
<DndProvider backend={TouchBackend} options={{ enableMouseEvents: true }}>
  {/* 应用内容 */}
</DndProvider>

性能优化建议

使用memo避免不必要的渲染

const DraggableItem = React.memo(function DraggableItem({ id, text }) {
  // 组件实现
});

减少收集函数复杂度

const [, drop] = useDrop(() => ({
  accept: 'ITEM',
  drop: (item) => ({ id: item.id }),
  // 简单的collect函数
  collect: (monitor) => ({
    isOver: monitor.isOver(),
    canDrop: monitor.canDrop(),
  }),
}));

高级用法示例

嵌套拖拽容器

function NestedContainer() {
  const [containers, setContainers] = useState([
    { id: 'container1', items: [...] },
    { id: 'container2', items: [...] },
  ]);

  const moveItemBetweenContainers = (itemId, fromContainerId, toContainerId) => {
    // 实现跨容器移动逻辑
  };

  return containers.map((container) => (
    <div key={container.id}>
      <h3>容器 {container.id}</h3>
      <DropZone
        containerId={container.id}
        onDrop={(item) => moveItemBetweenContainers(item.id, item.fromContainer, container.id)}
      >
        {container.items.map((item) => (
          <DraggableItem 
            key={item.id} 
            {...item} 
            fromContainer={container.id}
          />
        ))}
      </DropZone>
    </div>
  ));
}

拖拽预览自定义

const [, drag, preview] = useDrag(() => ({
  type: 'ITEM',
  item: { id },
}));

useEffect(() => {
  preview(getEmptyImage(), { captureDraggingState: true });
}, []);

// 自定义预览组件
<div ref={preview} style={{ position: 'absolute', opacity: 0 }} />

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

相关文章

react如何更新

react如何更新

更新 React 版本的方法 检查当前 React 版本 运行以下命令查看项目中安装的 React 版本: npm list react 更新 React 及相关依赖 通过 npm 或 yarn…

如何选购react

如何选购react

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

react如何同步

react如何同步

React 同步状态管理方法 在 React 中实现同步状态管理,可以通过以下多种方式实现: 使用 useState 和 useEffect 钩子 通过 useState 定义状态,使用 useEf…

如何安装react

如何安装react

安装React的方法 方法一:使用Create React App(官方推荐) Create React App是官方提供的脚手架工具,适合快速搭建React项目。确保已安装Node.js(建议版本≥…

java如何react

java如何react

在Java中使用React 要在Java项目中集成React,通常需要将React前端与Java后端结合使用。以下是几种常见的方法: 使用Spring Boot作为后端 Spring Boot是一个…

react如何引入

react如何引入

引入React的方法 React可以通过多种方式引入项目,具体取决于项目需求和开发环境。以下是常见的几种方法: 通过CDN引入 在HTML文件中直接通过CDN链接引入React和ReactDOM:…