---
title: "useDraggable 用法与示例"
description: "元素拖动。"
canonical: https://reactuse.com/zh-Hans/element/usedraggable/
---

# useDraggable

元素拖动

`useDraggable` 通过跟踪指针事件使任何 HTML 或 SVG 元素可拖拽，返回当前的 `x` 和 `y` 位置、表示元素是否正在被拖拽的布尔值以及程序化设置位置的函数。它支持指针、鼠标、触摸和触控笔输入，并可选择将移动限制在容器元素内。

### 使用场景

- 构建可拖拽面板、浮动工具栏或可调整大小的小部件
- 实现仪表板卡片或看板项目的拖拽重新定位功能
- 创建元素需要自由移动的交互式图表或编辑器

### 注意事项

- **触摸支持**：在可拖拽元素的 CSS 上设置 `touch-action: none` 以防止触摸设备上的浏览器滚动干扰。
- **容器边界**：使用 `containerElement` 选项将拖拽限制在父元素内。hook 将自动计算边界。
- **回调**：`onStart`、`onMove` 和 `onEnd` 回调提供精细控制。从 `onStart` 返回 `false` 可阻止拖拽开始。
- **清理**：所有指针事件监听器在卸载时自动移除。

## Usage

### Fixed Demo

```tsx live

function Demo() {
  const el = useRef<HTMLDivElement>(null);

  const [initialValue, setInitialValue] = useState({ x: 200 / 2.2, y: 120 });

  useEffect(() => {
    setInitialValue({ x: window.innerWidth / 2.2, y: 120 });
  }, []);

  const [x, y, isDragging] = useDraggable(el, {
    initialValue,
    preventDefault: true,
  });

  return (
    <div>
      <p style={{ textAlign: "center" }}>检查浮动框</p>
      <div
        ref={el}
        style={{
          position: "fixed",
          cursor: "move",
          zIndex: 10,
          touchAction: "none",
          padding: 10,
          border: "solid 1px",
          left: x,
          top: y,
        }}
      >
        {isDragging ? "拖拽中！" : "👋 拖拽我！"}
        <div>
          我在 {Math.round(x)}, {Math.round(y)}
        </div>
      </div>
    </div>
  );
};
```

### Relative Demo

```tsx live
function Demo() {
  const el = useRef<HTMLDivElement>(null);
  const scope = useRef<HTMLDivElement>(null);

  const initialValue = { x: 200 / 2.2, y: 120 };

  const [x, y, isDragging, setPosition] = useDraggable(el, {
    initialValue,
    preventDefault: true,
    containerElement: scope,
  });

  return (
    <div
      ref={scope}
      style={{
        width: 500,
        height: 500,
        border: "1px solid blue",
        position: "relative",
      }}
    >
      <button
        style={{ textAlign: "center" }}
        onClick={() => {
          setPosition({
            x: 250,
            y: 250,
          });
        }}
      >
        设置位置
      </button>
      <div
        ref={el}
        style={{
          position: "absolute",
          cursor: "move",
          zIndex: 10,
          touchAction: "none",
          padding: 10,
          border: "solid 1px",
          left: x,
          top: y,
          whiteSpace: "nowrap",
        }}
      >
        {isDragging ? "拖拽中！" : "👋 拖拽我！"}
        <div style={{ whiteSpace: "nowrap" }}>
          我在 {Math.round(x)}, {Math.round(y)}
        </div>
      </div>
    </div>
  );
}
```

%%API%%