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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 09:33:15