如何实现横向拖拽排序功能?图片库仅支持纵向拖拽问题排查
解决图片库横向拖拽排序仅支持纵向的问题
我正在实现拖拽排序功能,图片库(gallery)中只有将图片拖拽到其他图片下方时才会改变位置,仅支持纵向拖拽,但数据表(datasheet)的拖拽功能正常。
原生JavaScript代码如下:
const enableDragSort = className => { // 获取所有.gallery或.datasheet类的子元素 [...document.getElementsByClassName(className)].forEach(enableDragList); } const enableDragList = container => { // 为容器内的每个子元素添加可拖拽属性 [...container.children].forEach(enableDragItem); } const enableDragItem = item => { item.setAttribute('draggable', true); item.ondrag = handleDrag; item.ondragend = handleDrop; } const handleDrag = event => { const item = event.target.closest('[draggable]'); item.classList.add('drag-sort-active'); const container = item.parentElement; const x = event.clientX; const y = event.clientY; let swap = document.elementFromPoint(x, y) ?? item; if (container === swap.parentElement) { swap = (swap !== item.nextSibling) ? swap : swap.nextSibling; container.insertBefore(item, swap); } } const handleDrop = ({ target }) => { const item = target.closest('[draggable]'); item.classList.remove('drag-sort-active'); } // 启用拖拽排序 enableDragSort('gallery'); // 工作异常 enableDragSort('datasheet'); // 工作正常
问题原因
当前handleDrag函数的插入逻辑只适配了纵向排列的元素(比如datasheet的垂直列表):它通过判断目标元素是否为当前元素的下一个兄弟来决定插入位置,完全忽略了横向布局中“左右拖拽”的场景。当在gallery(横向布局)中拖拽图片到目标元素的左侧或右侧时,无法正确触发位置交换,只有拖拽到下方时才会生效。
解决方案
修改handleDrag函数,通过计算鼠标相对于目标元素的位置,动态判断插入方向,适配横向/纵向布局:
const enableDragSort = className => { [...document.getElementsByClassName(className)].forEach(enableDragList); } const enableDragList = container => { [...container.children].forEach(enableDragItem); } const enableDragItem = item => { item.setAttribute('draggable', true); item.ondrag = handleDrag; item.ondragend = handleDrop; } const handleDrag = event => { const item = event.target.closest('[draggable]'); item.classList.add('drag-sort-active'); const container = item.parentElement; const x = event.clientX; const y = event.clientY; let swap = document.elementFromPoint(x, y) ?? item; swap = swap.closest('[draggable]') ?? item; if (container === swap.parentElement && swap !== item) { // 获取目标元素的边界信息 const swapRect = swap.getBoundingClientRect(); // 计算目标元素的中心坐标 const swapCenterX = swapRect.left + swapRect.width / 2; const swapCenterY = swapRect.top + swapRect.height / 2; // 根据鼠标位置相对于目标中心的位置,判断插入方向 const insertBefore = (x < swapCenterX && container.style.flexDirection === 'row') || (y < swapCenterY && container.style.flexDirection !== 'row'); if (insertBefore) { container.insertBefore(item, swap); } else { container.insertBefore(item, swap.nextSibling); } } } const handleDrop = ({ target }) => { const item = target.closest('[draggable]'); item.classList.remove('drag-sort-active'); } // 启用拖拽排序 enableDragSort('gallery'); // 现在正常工作 enableDragSort('datasheet'); // 保持正常工作
关键修改点
- 精准获取目标元素:通过
swap.closest('[draggable]')确保拿到的是可拖拽的子元素,避免误触容器内的其他元素 - 计算元素中心坐标:用
getBoundingClientRect()获取目标元素的位置和尺寸,计算中心坐标 - 动态判断插入方向:
- 横向布局(flex row):根据鼠标x坐标是否小于目标中心x,决定插入到前面还是后面
- 纵向布局:根据鼠标y坐标是否小于目标中心y,决定插入方向
- 灵活插入位置:不再依赖固定的兄弟节点判断,而是根据方向选择插入到目标元素前或后
内容的提问来源于stack exchange,提问作者Jonathan Silva
相关产品推荐
相关产品推荐

