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

React拖拽Div位置留存及拖拽光标自定义问题求助

React拖拽Div问题修复方案

问题1:拖拽结束后Div回到左上角的解决方法

核心问题是没有持久化拖拽后的位置状态,每次拖拽都从初始原点计算偏移。要解决这个问题,需要用状态保存元素的当前位置,拖拽时基于这个位置计算新的偏移量:

  1. 在组件中添加状态存储当前位置:
const [position, setPosition] = useState({ x: 0, y: 0 });
  1. 修改鼠标按下时的逻辑,记录初始点击位置相对于元素当前位置的偏移:
const handleMouseDown = (e) => {
  // 记录点击点相对于元素左上角的偏移,而非页面原点
  const offsetX = e.clientX - position.x;
  const offsetY = e.clientY - position.y;
  
  const handleMouseMove = (moveEvent) => {
    // 基于当前位置和偏移计算新位置
    const newX = moveEvent.clientX - offsetX;
    const newY = moveEvent.clientY - offsetY;
    setPosition({ x: newX, y: newY });
  };
  
  const handleMouseUp = () => {
    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
  };
  
  document.addEventListener('mousemove', handleMouseMove);
  document.addEventListener('mouseup', handleMouseUp);
};
  1. 元素的样式直接使用状态中的position:
<div
  className="draggable"
  style={{ left: `${position.x}px`, top: `${position.y}px` }}
  onMouseDown={handleMouseDown}
>
  可拖拽Div
</div>

问题2:拖拽时显示抓取光标并移除地球图标

地球图标是浏览器默认拖拽行为(比如文本选择)导致的,需要阻止默认事件并设置光标样式:

  1. 在CSS中设置光标样式:
.draggable {
  position: absolute;
  width: 100px;
  height: 100px;
  background: blue;
  cursor: grab; /* 未拖拽时的光标 */
  user-select: none; /* 禁止文本选择,避免触发默认行为 */
}

.draggable:active {
  cursor: grabbing; /* 拖拽中的光标 */
}
  1. 在handleMouseDown中添加阻止默认事件:
const handleMouseDown = (e) => {
  e.preventDefault(); // 阻止浏览器默认拖拽行为
  // ... 其余代码不变
};

完整修改后的代码示例

import { useState } from 'react';
import './styles.css';

export default function App() {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseDown = (e) => {
    e.preventDefault();
    const offsetX = e.clientX - position.x;
    const offsetY = e.clientY - position.y;

    const handleMouseMove = (moveEvent) => {
      const newX = moveEvent.clientX - offsetX;
      const newY = moveEvent.clientY - offsetY;
      setPosition({ x: newX, y: newY });
    };

    const handleMouseUp = () => {
      document.removeEventListener('mousemove', handleMouseMove);
      document.removeEventListener('mouseup', handleMouseUp);
    };

    document.addEventListener('mousemove', handleMouseMove);
    document.addEventListener('mouseup', handleMouseUp);
  };

  return (
    <div className="App">
      <div
        className="draggable"
        style={{ left: `${position.x}px`, top: `${position.y}px` }}
        onMouseDown={handleMouseDown}
      >
        可拖拽Div
      </div>
    </div>
  );
}
.App {
  font-family: sans-serif;
  text-align: center;
  height: 100vh;
  position: relative;
}

.draggable {
  position: absolute;
  width: 100px;
  height: 100px;
  background: blue;
  cursor: grab;
  user-select: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.draggable:active {
  cursor: grabbing;
}

内容的提问来源于stack exchange,提问作者kapv89

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:15:57