拖拽调整对象priority时函数异常:目标项优先级未正确更新
问题:拖拽调整数组对象priority值时异常(低优先级项拖至高位置失效)
我编写了updatePriorities函数用于拖拽调整数组中对象的priority值,但发现当低优先级项拖到高优先级位置时,目标项的priority无法正确更新;反之高优先级项拖到低位置时运行正常。
原函数代码
export const updatePriorities = (data, draggedItem, targetItem) => { const draggedItemPriority = draggedItem?.priority; const targetItemPriority = targetItem?.priority; if (draggedItemPriority === undefined || targetItemPriority === undefined || draggedItemPriority === null || targetItemPriority === null) { return data; } const minPriority = Math.min(draggedItemPriority, targetItemPriority); const maxPriority = Math.max(draggedItemPriority, targetItemPriority); const newData = map(data, (item) => { if (item.priority === draggedItemPriority) { return { ...item, priority: targetItemPriority }; } else if (item.priority >= minPriority && item.priority < maxPriority) { const priorityOffset = targetItemPriority < draggedItemPriority ? 1 : -1; return { ...item, priority: item.priority + priorityOffset }; } else if (item.priority === targetItemPriority) { return { ...item, priority: draggedItemPriority }; } return item; }); return orderBy(newData, 'priority'); };
测试数据
const mockedData = [ { name: 'Item 0', priority: 0 }, { name: 'Item 1', priority: 1 }, { name: 'Item 2', priority: 2 }, { name: 'Item 3', priority: 3 }, { name: 'Item 4', priority: 4 }, { name: 'Item 5', priority: 5 } ]; const mockedDraggedItem1 = mockedData[1]; // priority=1 const mockedTargetItem1 = mockedData[3]; // priority=3
错误结果与预期结果
调用updatePriorities(mockedData, mockedDraggedItem1, mockedTargetItem1)后得到错误结果:
[ {name: "Item 0", priority: 0}, {name: "Item 2", priority: 1}, {name: "Item 3", priority: 1}, // 此处错误,应为2 {name: "Item 1", priority: 3}, {name: "Item 4", priority: 4}, {name: "Item 5", priority: 5} ]
预期结果:
[ {name: "Item 0", priority: 0}, {name: "Item 2", priority: 1}, {name: "Item 3", priority: 2}, {name: "Item 1", priority: 3}, {name: "Item 4", priority: 4}, {name: "Item 5", priority: 5} ]
问题原因与修复方案
问题根源
原逻辑的核心问题是遍历过程中修改的值干扰了后续判断:
当拖拽低优先级项(priority=1)到高位置(priority=3)时:
- 先处理原拖拽项(priority=1),将其改为3;
- 处理到priority=2的项时,因为
min=1,max=3,满足>=min && <max,所以减1变成1; - 最后处理原目标项(priority=3)时,此时拖拽项的priority已经被改成3,导致
item.priority === draggedItemPriority条件先触发,跳过了item.priority === targetItemPriority的分支,目标项的priority未被正确修改。
修复后的代码
export const updatePriorities = (data, draggedItem, targetItem) => { const draggedItemPriority = draggedItem?.priority; const targetItemPriority = targetItem?.priority; if (draggedItemPriority === undefined || targetItemPriority === undefined || draggedItemPriority === null || targetItemPriority === null) { return data; } // 提前判断拖拽方向:低优先级拖到高位置为true const isDraggingUp = targetItemPriority > draggedItemPriority; const newData = data.map(item => { const currentPriority = item.priority; // 先处理拖拽项与目标项的交换,基于原始优先级判断 if (currentPriority === draggedItemPriority) { return { ...item, priority: targetItemPriority }; } if (currentPriority === targetItemPriority) { return { ...item, priority: draggedItemPriority }; } // 根据拖拽方向处理中间项 if (isDraggingUp) { // 低优先级拖到高位置:中间项(原拖拽项+1 到 目标项-1)减1 if (currentPriority > draggedItemPriority && currentPriority < targetItemPriority) { return { ...item, priority: currentPriority - 1 }; } } else { // 高优先级拖到低位置:中间项(原目标项+1 到 拖拽项-1)加1 if (currentPriority > targetItemPriority && currentPriority < draggedItemPriority) { return { ...item, priority: currentPriority + 1 }; } } return item; }); return orderBy(newData, 'priority'); };
修复关键点
- 基于原始优先级判断:全程使用未修改的
draggedItemPriority和targetItemPriority做条件判断,避免遍历中修改的值干扰逻辑; - 拆分拖拽方向:明确区分向上(低→高)和向下(高→低)拖拽的场景,分别处理中间项的范围,避免用min/max导致的逻辑模糊;
- 调整判断顺序:先处理拖拽项与目标项的交换,再处理中间项,避免条件冲突。
验证结果
调用修复后的函数,会得到预期的正确结果,目标项的priority被正确更新为2,中间项的优先级也符合拖拽排序逻辑。
内容的提问来源于stack exchange,提问作者Boky
相关产品推荐
相关产品推荐

