You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确修复数组对象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. 边界校验增强:增加了拖拽项/目标项在数组中存在性的判断,避免无效操作
  2. 单独处理同优先级场景:先调整目标项优先级加1,再处理其他项的偏移
  3. 精准调整区间项:根据拖拽方向(从低到高/高到低)对区间内的非拖拽/目标项做对应偏移
  4. 强制去重逻辑:用Map确保最终所有优先级唯一,再按优先级排序
  5. 避免原数据污染:全程操作数组副本,不修改输入的原数据

内容的提问来源于stack exchange,提问作者Boky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 11:27:35