如何解决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会一同被拖拽,不符合预期。
问题原因
- 自定义拖拽逻辑与
react-draggable内置逻辑冲突,导致位置控制混乱; - 拖拽事件未阻止冒泡,父级
Draggable组件会触发跟随移动; - 子组件的拖拽边界容器未正确设置,
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
相关产品推荐
相关产品推荐

