拖拽树形结构时子节点位置错乱怎么办?

A. 宝娥 阅读 3

我在用原生 JS 实现一个可拖拽的树形菜单,父节点展开后拖动子节点,结果一松手子节点就跑到根节点下面去了。

我试过在 drop 事件里打印目标节点,发现 e.target 指向的是父容器而不是具体的子项。是不是因为事件冒泡导致判断错了插入位置?

这是我的关键逻辑:

function handleDrop(e) {
  e.preventDefault();
  const draggedId = e.dataTransfer.getData('text/plain');
  const targetNode = e.target; // 这里拿到的经常不是叶子节点
  // ... 插入逻辑
}
我来解答 赞 6 收藏
二维码
手机扫码查看
1 条解答
Mc.艳丽
Mc.艳丽 Lv1
第一步,我们要解决的问题是因为事件冒泡导致我们在 drop 事件中获取的目标节点不准确。当你拖拽一个元素并释放时,drop 事件会冒泡到最外层的容器,而不是你实际想要的那个子元素。

第二步,我们可以使用 event.path 或者 event.composedPath() 来获取事件触发路径,这样可以找到具体被拖放到哪个子元素上。不过需要注意的是,event.path 并不是所有浏览器都支持,但我们可以用兼容的方式来处理。

第三步,我们要修改 handleDrop 函数,让它能够正确地找到目标子元素,并且将被拖拽的元素插入到正确的位置。

第四步,为了确保代码的兼容性和正确性,我们可以先检查 event.path 是否存在,如果不存在则使用 event.composedPath(),最后再检查这些路径中的元素是否是我们需要的目标元素。

下面是修改后的代码示例:

function handleDrop(e) {
e.preventDefault();
const draggedId = e.dataTransfer.getData('text/plain');

// 获取事件冒泡路径
const path = e.path || (e.composedPath && e.composedPath());

let targetNode = null;

// 遍历路径,找到第一个是我们的子元素的节点
for (let i = 0; i < path.length; i++) {
if (path[i].classList && path[i].classList.contains('tree-node')) { // 假设我们的子元素都有 tree-node 类名
targetNode = path[i];
break;
}
}

// 如果找到了目标节点,进行插入操作
if (targetNode) {
const draggedElement = document.getElementById(draggedId);
targetNode.parentNode.insertBefore(draggedElement, targetNode.nextSibling);
} else {
console.warn('Dropped on an invalid target');
}
}


这里假设我们的每个子节点都有一个 tree-node 的类名,你可以根据实际情况调整这个条件。通过这种方式,我们可以在 drop 事件中更准确地找到目标子元素,并将被拖拽的元素插入到正确的位置。

希望这能解决你遇到的问题,如果还有其他地方不明白,尽管问我。
点赞
2026-03-24 20:00