如何正确修复数组对象priority替换函数的重复优先级处理问题
问题需求
需要实现拖拽排序场景下的优先级更新逻辑,规则如下:
- 将拖拽项(draggedItem)的优先级替换为目标项(targetItem)的优先级
- 若两者优先级相同:拖拽项保留原优先级,目标项优先级加1以避免重复
- 其余对象的优先级需根据新的拖拽项和目标项优先级正确调整
- 最终数组中所有对象的优先级必须唯一,并按优先级排序
原实现代码
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 }; } return item; }); return orderBy(newData, 'priority'); };
问题分析
原函数默认输入数组的优先级是唯一的,当存在重复优先级时会出现逻辑失效:
- 多个项拥有相同的
draggedItemPriority时,会被批量修改为targetItemPriority,直接导致优先级重复 - 区间内优先级偏移逻辑未考虑重复值,会出现调整后仍有重复的情况
- 未单独处理拖拽项与目标项优先级相同的场景,无法触发目标项加1的规则
修改后的实现
const updatePriorities = (data, draggedItem, targetItem) => { // 边界判断:优先级无效或项不存在时返回原数组副本 const draggedPriority = draggedItem?.priority; const targetPriority = targetItem?.priority; if (draggedPriority == null || targetPriority == null) return [...data]; const draggedIndex = data.findIndex(item => item === draggedItem); const targetIndex = data.findIndex(item => item === targetItem); if (draggedIndex === -1 || targetIndex === -1) return [...data]; // 复制原数组,避免修改原数据 let newData = data.map(item => ({ ...item })); let newDraggedPriority = targetPriority; let newTargetPriority = targetPriority; // 处理拖拽项与目标项优先级相同的场景 if (draggedPriority === targetPriority) { newTargetPriority = targetPriority + 1; newData[targetIndex].priority = newTargetPriority; } else { // 先更新拖拽项的优先级为目标项的优先级 newData[draggedIndex].priority = newDraggedPriority; } // 确定拖拽方向与需要调整的优先级范围 const originalMin = Math.min(draggedPriority, targetPriority); const originalMax = Math.max(draggedPriority, targetPriority); const isDraggingToHigher = draggedPriority < targetPriority; // 调整其余项的优先级 newData = newData.map(item => { if (item === draggedItem || item === targetItem) return item; const currentPriority = item.priority; // 调整原拖拽与目标区间内的项 if (currentPriority >= originalMin && currentPriority <= originalMax) { return { ...item, priority: isDraggingToHigher ? currentPriority - 1 : currentPriority + 1 }; } // 原优先级相同时,调整高于新目标优先级的项 if (draggedPriority === targetPriority && currentPriority >= newTargetPriority) { return { ...item, priority: currentPriority + 1 }; } return item; }); // 确保优先级唯一并排序:用Map去重,键为优先级,值为对应项 const uniquePriorityMap = new Map(); newData.forEach(item => uniquePriorityMap.set(item.priority, item)); return Array.from(uniquePriorityMap.values()).sort((a, b) => a.priority - b.priority); };
关键修改点
- 边界校验增强:增加了拖拽项/目标项在数组中存在性的判断,避免无效操作
- 单独处理同优先级场景:先调整目标项优先级加1,再处理其他项的偏移
- 精准调整区间项:根据拖拽方向(从低到高/高到低)对区间内的非拖拽/目标项做对应偏移
- 强制去重逻辑:用
Map确保最终所有优先级唯一,再按优先级排序 - 避免原数据污染:全程操作数组副本,不修改输入的原数据
内容的提问来源于stack exchange,提问作者Boky
相关产品推荐
相关产品推荐

