React中使用@dnd-kit/core时,如何在卡片Resize时禁用拖拽
解决拖拽与调整大小冲突的问题
要解决调整卡片大小时触发拖拽的问题,核心是在 resize 过程中完全禁用拖拽功能,同时确保状态同步和事件不冲突。以下是几种经过验证的可行方案:
方案一:共享Resize状态,直接禁用Draggable
这是最直接的方式,通过上层组件维护isResizing状态,传递给Draggable组件的isDragDisabled属性,同时阻止resize手柄的事件冒泡,避免dnd-kit捕获到拖拽触发事件。
步骤1:上层组件维护状态并传递回调
修改Cards组件,添加isResizing状态,并把状态更新函数传递给子组件:
import { useState } from 'react'; import { DndContext, Draggable } from '@dnd-kit/core'; const Cards = () => { const [isResizing, setIsResizing] = useState(false); return ( <DndContext> <div className="flex flex-col space-y-4 w-screen h-screen bg-slate-300 p-5"> {/* 用isResizing控制拖拽禁用 */} <Draggable id={1} isDragDisabled={isResizing}> <PerformanceBars onResizeStart={() => setIsResizing(true)} onResizeStop={() => setIsResizing(false)} /> </Draggable> </div> </DndContext> ); };
步骤2:在CardBody中绑定resize回调并阻止事件冒泡
修改负责resize的CardBody组件,在resize手柄上添加stopPropagation,防止mousedown事件被dnd-kit的拖拽监听器捕获:
import { Resizable } from 're-resizable'; const CardBody = ({ children, onResizeStart, onResizeStop }) => { const handleResizeStart = (e) => { e.stopPropagation(); // 阻止事件冒泡到Draggable容器 onResizeStart(); }; return ( <Resizable onResizeStart={handleResizeStart} onResizeStop={onResizeStop} // 你的resize配置(比如宽高限制、手柄位置等) > <div className="card-body">{children}</div> </Resizable> ); };
方案二:手动管理拖拽监听器(更灵活的控制)
如果Draggable组件的isDragDisabled不生效,可以用@dnd-kit的useDraggable钩子手动控制拖拽监听器的绑定,只在非resize状态下绑定拖拽事件:
import { useState } from 'react'; import { DndContext, useDraggable } from '@dnd-kit/core'; // 自定义可拖拽卡片组件 const DraggableCard = ({ isResizing, children }) => { const { attributes, listeners, setNodeRef, transform } = useDraggable({ id: 1, disabled: isResizing, // 直接禁用拖拽逻辑 }); // 拖拽时的位移样式 const dragStyle = transform ? { transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, } : {}; return ( <div ref={setNodeRef} style={dragStyle} {...attributes}> {/* 仅在非resize状态下绑定拖拽监听器 */} {isResizing ? children : <div {...listeners}>{children}</div>} </div> ); }; const Cards = () => { const [isResizing, setIsResizing] = useState(false); return ( <DndContext> <div className="flex flex-col space-y-4 w-screen h-screen bg-slate-300 p-5"> <DraggableCard isResizing={isResizing}> <PerformanceBars onResizeStart={() => setIsResizing(true)} onResizeStop={() => setIsResizing(false)} /> </DraggableCard> </div> </DndContext> ); };
方案三:动态调整dnd-kit的激活约束
如果前两种方案无效,可以通过DndContext的activationConstraint动态设置拖拽激活条件,在resize时设置无限延迟,完全阻止拖拽激活:
import { useState } from 'react'; import { DndContext, Draggable } from '@dnd-kit/core'; const Cards = () => { const [isResizing, setIsResizing] = useState(false); // 根据resize状态动态调整激活约束 const activationConstraint = isResizing ? { delay: Infinity, // 无限延迟,永远不激活拖拽 tolerance: Infinity, } : { delay: 0, tolerance: 0, }; return ( <DndContext activationConstraint={activationConstraint}> <div className="flex flex-col space-y-4 w-screen h-screen bg-slate-300 p-5"> <Draggable id={1}> <PerformanceBars onResizeStart={() => setIsResizing(true)} onResizeStop={() => setIsResizing(false)} /> </Draggable> </div> </DndContext> ); };
为什么之前的方法可能没生效?
- 状态传递错误:如果
isResizing状态没有正确传递到Draggable组件,禁用逻辑不会触发。 - 事件冒泡:resize手柄的
mousedown事件被dnd-kit捕获,导致拖拽触发,需要用stopPropagation阻止。 - 配置时机问题:
activationConstraint或modifiers的动态更新可能没有同步到dnd-kit的内部状态,需要确保状态更新后组件重新渲染。
内容的提问来源于stack exchange,提问作者Yash
相关产品推荐
相关产品推荐

