双层模态框中dnd-kit组件需双击才移动的问题排查求助
模态框内多容器拖拽需双击触发的问题排查与解决方向
我在第二层模态框中实现多容器拖拽功能时遇到异常:组件可以在容器间移动,但必须双击才能触发移动操作。我怀疑问题出在handleDragOver函数中,相关代码如下:
function handleDragOver(event) { console.log("start drag over"); const { active, over } = event; const { id } = active; const { id: overId } = over; console.log("active", id); console.log("over", overId); // Find the containers var activeContainer; var overContainer; findContainer(id) .then(async (data) => { activeContainer = await data; await findContainer(overId).then(async (d) => { overContainer = await d; }); }) .then(() => { console.log("activeContainer", activeContainer); console.log("overContainer", overContainer); if ( !activeContainer || !overContainer || activeContainer === overContainer ) { return; } setGroupItems((prev) => { const activeItems = prev[activeContainer]; const overItems = prev[overContainer]; const activeIndex = activeItems.findIndex((i) => i.id === id); const overIndex = overItems.findIndex((i) => i.id === overId); console.log("aIndex", activeIndex); console.log("oIndex", overIndex); let newIndex; newIndex = overIndex >= 0 ? overIndex + 1 : overItems.length + 1; return { ...prev, [activeContainer]: [ ...prev[activeContainer].filter((item) => item.id !== active.id) ], [overContainer]: [ ...prev[overContainer].slice(0, newIndex), groupItems[activeContainer][activeIndex], ...prev[overContainer].slice(newIndex, prev[overContainer].length) ] }; }); }); }
我已将示例项目上传至CodeSandBox。
解决方向:
模态框事件层级冲突:第二层模态框的遮罩或内部元素可能抢占了拖拽的
dragstart事件,导致单次点击无法触发拖拽初始化。可以给拖拽元素添加dragstart事件日志,验证该事件是否在首次点击时触发;同时检查模态框的事件绑定,确保没有阻止拖拽相关事件的冒泡或捕获。异步逻辑延迟导致状态更新滞后:原代码中嵌套的
then异步调用会让setGroupItems的执行被延迟,首次拖拽时状态更新还未完成,第二次点击时异步操作才结束,看起来像是需要双击才能生效。建议重构为线性的async/await逻辑,确保状态更新在异步操作完成后立即执行:
async function handleDragOver(event) { console.log("start drag over"); const { active, over } = event; const { id } = active; const { id: overId } = over; try { const activeContainer = await findContainer(id); const overContainer = await findContainer(overId); if (!activeContainer || !overContainer || activeContainer === overContainer) { return; } setGroupItems((prev) => { const activeItems = prev[activeContainer]; const overItems = prev[overContainer]; const activeIndex = activeItems.findIndex((i) => i.id === id); const overIndex = overItems.findIndex((i) => i.id === overId); let newIndex = overIndex >= 0 ? overIndex + 1 : overItems.length; // 必须使用prev状态获取最新值,避免闭包捕获旧状态 return { ...prev, [activeContainer]: prev[activeContainer].filter(item => item.id !== active.id), [overContainer]: [ ...prev[overContainer].slice(0, newIndex), prev[activeContainer][activeIndex], ...prev[overContainer].slice(newIndex) ] }; }); } catch (err) { console.error("拖拽处理出错:", err); } }
状态更新依赖旧值的问题:原代码中
setGroupItems里直接使用groupItems[activeContainer][activeIndex],这会捕获组件渲染时的旧状态值,而非最新的prev状态。当异步操作延迟时,这个旧值可能导致首次拖拽未正确更新状态,需要改为使用prev[activeContainer][activeIndex]获取最新状态。拖拽库兼容性配置:如果使用了第三方拖拽库,需确认库在模态框场景下的适配性。部分拖拽库需要额外配置(如设置拖拽预览层的
zIndex、使用portal挂载拖拽元素),确保拖拽事件能被正确捕获,预览层能正常显示。
内容的提问来源于stack exchange,提问作者Jenny Huoh
相关产品推荐
相关产品推荐

