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

如何解决React拖拽组件中事件冒泡引发的父组件联动拖拽问题?

解决嵌套Draggable组件拖拽时父容器跟随移动的问题

需求

初始页面顶部设有按钮,点击按钮为现有div创建父级div,所有div需能在自身父级div范围内拖拽。

原代码

import React, { useState } from "react";
import Draggable from "react-draggable";

function ParentDraggable(props) {
  const [x, setX] = useState(0);
  const [y, setY] = useState(0);

  const handleMouseDown = (e) => {
    let startX = e.clientX;
    let startY = e.clientY;

    const handleMouseMove = (e) => {
      setX(x + e.clientX - startX);
      setY(y + e.clientY - startY);
      startX = e.clientX;
      startY = e.clientY;
    };

    document.addEventListener("mousemove", handleMouseMove);

    document.addEventListener("mouseup", () => {
      document.removeEventListener("mousemove", handleMouseMove);
    });
  };

  return (
    <Draggable bounds="parent" handle=".handle">
      <div
        style={{
          position: "relative",
          top: y,
          left: x,
          border: "1px solid black",
          width: `${props.w}px`,
          height: `${props.h}px`
        }}
      >
        <div
          style={{
            height: 20,
            backgroundColor: "gray"
          }}
          onMouseDown={handleMouseDown}
          className="handle"
        >
          Title Bar
        </div>
        {props.children}
      </div>
    </Draggable>
  );
}

function App() {
  const [parents, setParents] = useState([]);
  const [w, setW] = useState(200);
  const [h, setH] = useState(200);

  const handleAddParent = () => {
    setParents([
      <ParentDraggable w={w} h={h}>
        {parents}
      </ParentDraggable>
    ]);
    setW((prev) => prev + 100);
    setH((prev) => prev + 100);
  };

  return (
    <>
      <button onClick={handleAddParent}>AddParent</button>

      <div style={{ height: "98vh" }}>{parents}</div>
    </>
  );
}

export default App;

当前问题

拖拽任意子组件时,其父级div会一同被拖拽,不符合预期。

问题原因

  1. 自定义拖拽逻辑与react-draggable内置逻辑冲突,导致位置控制混乱;
  2. 拖拽事件未阻止冒泡,父级Draggable组件会触发跟随移动;
  3. 子组件的拖拽边界容器未正确设置,bounds="parent"无法生效在目标容器上。

解决方案及修改后代码

import React, { useState } from "react";
import Draggable from "react-draggable";

function ParentDraggable(props) {
  // 阻止拖拽事件冒泡,避免父级Draggable触发
  const handleDragStart = (e) => {
    e.stopPropagation();
  };

  return (
    <Draggable bounds="parent" handle=".handle" onStart={handleDragStart}>
      <div
        style={{
          position: "relative",
          border: "1px solid black",
          width: `${props.w}px`,
          height: `${props.h}px`,
          overflow: "hidden"
        }}
      >
        <div
          style={{
            height: 20,
            backgroundColor: "gray",
            cursor: "move"
          }}
          className="handle"
        >
          Title Bar
        </div>
        {/* 为子组件提供正确的拖拽边界容器 */}
        <div style={{ position: "absolute", top: 20, left: 0, right: 0, bottom: 0 }}>
          {props.children}
        </div>
      </div>
    </Draggable>
  );
}

function App() {
  const [parents, setParents] = useState(null);
  const [w, setW] = useState(200);
  const [h, setH] = useState(200);

  const handleAddParent = () => {
    // 正确嵌套新的父容器
    setParents(prev => (
      <ParentDraggable w={w} h={h}>
        {prev}
      </ParentDraggable>
    ));
    setW(prev => prev + 100);
    setH(prev => prev + 100);
  };

  return (
    <>
      <button onClick={handleAddParent}>AddParent</button>
      <div style={{ height: "98vh", position: "relative" }}>{parents}</div>
    </>
  );
}

export default App;

修改说明

  • 移除自定义拖拽逻辑,完全依赖react-draggable内置功能,避免逻辑冲突;
  • 在onStart事件中调用e.stopPropagation(),阻止拖拽事件冒泡到父级容器;
  • 添加绝对定位的子容器,作为子组件的拖拽边界容器,确保bounds="parent"生效;
  • 调整setParents写法,正确实现嵌套容器的累加逻辑;
  • 为拖拽手柄添加cursor: move,优化交互体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 03:01:00