React DnD嵌套拖拽异常,ref.current始终返回外层嵌套元素如何解决
解决方案
你遇到的问题核心是嵌套的drop目标事件冒泡、以及热区没有区分父元素自身区域和子元素占位区域两个原因导致的,按以下步骤修改即可解决:
- 完善hover逻辑的触发条件
你已经添加了monitor.isOver({ shallow: true })的浅检测,再新增父元素自身热区的判断即可,避免鼠标落在子元素区域时触发外层父元素的hover回调,修改后的hover代码如下:
hover(item, monitor) { if (!ref.current) return; // 浅检测:只触发当前直接hover的drop目标,阻止冒泡到父级drop if (!monitor.isOver({ shallow: true })) return; const dragId = item.id; const hoverId = id; // 避免自身拖拽触发 if (dragId === hoverId) return; // 新增:判断鼠标是否落在当前元素自身的内容区域,排除子元素占用区域 const hoverBoundingRect = ref.current.getBoundingClientRect(); // 取当前Card的第一个子节点(存放text的标题div)的高度作为自身热区范围 const selfTitleHeight = ref.current.firstChild.getBoundingClientRect().height; const clientOffset = monitor.getClientOffset(); const hoverClientY = clientOffset.y - hoverBoundingRect.top; // 鼠标超出自身标题区域,说明hover的是子元素,直接终止当前drop逻辑 if (hoverClientY > selfTitleHeight) return; // 原有Y轴中点判断逻辑保留 const hoverMiddleY = selfTitleHeight / 2; // 同层级向下拖拽时只有鼠标超过中点才触发位置交换 if (item.path.length === path.length && item.index < index && hoverClientY < hoverMiddleY) return; // 同层级向上拖拽时只有鼠标低于中点才触发位置交换 if (item.path.length === path.length && item.index > index && hoverClientY > hoverMiddleY) return; // 执行跨层级/同层级移动逻辑 moveCard(item, { id, path, parentId }); // 更新拖拽元素的路径信息 item.path = path; item.parentId = parentId; item.index = index; }
替换扁平索引为层级路径标识
原有逻辑使用全局扁平的index判断位置,完全不支持嵌套结构,需要给每个元素新增path(数组类型,存储从根节点到当前元素的层级索引)、parentId(父级元素ID,没有则为null)两个属性,替代原有的单index字段,moveCard逻辑根据path来更新嵌套的数据源即可实现跨层级拖拽排序。辅助优化
嵌套数据源建议用树形结构存储,每个节点统一存id、text、type、children四个核心属性,更新时递归查找对应节点操作即可,不需要额外维护扁平映射表。
内容的提问来源于stack exchange,提问作者user0227
相关产品推荐
相关产品推荐

