高性能分组列表设计-2

July 30, 2021
project

通过改变列表项位置更新分组关系

要解决的问题

  • 移动分组时,分组所有的子项都要移动,且保持相对位置和关系不变
  • 批量移动未分组列表项到分组内时,相对位置应不变
  • 已分组列表项移动出分组范围时应,应解除分组关系

分析

当分组移动时,所有分组的子项都不变,首先需要搜索到分组内所有的子项。然后记录该子项在分组内的相对位置,以及在整体列表中的位置。 这样在移动时,方便进行计算。

整体来讲,这个移动过程中的搜索部分将使用深度优先搜索的一种变种。移动后的排序,只需遵守搜索中分组和其子项的相对顺序遍历即可。

分组子项搜索流程如下:

typescript
if (!groupCache.includes(hasGroup)) {
      //组件的分组不在查询的分组内。弹出所有的分组缓存
      groupCache = [];
      return;
    } else {
      result.push(item); //组件的分组在分组缓存中

      if (hasGroup !== groupCache[groupCache.length - 1]) {
        // 如果组件的分组不在缓存的顶层
        const hasGroupCacheIndex = groupCache.indexOf(hasGroup);
        groupCache = groupCache.slice(0, hasGroupCacheIndex + 1);
      }
      if (compDatas[item].compCode === 'group') {
        // 组件本身是分组组件
        groupCache.push(item);
      }
    }

列表项排序流程如下:

typescript

  /**
  * compDatas 所有的列表项{[code]:{ config: { [groupCode]:groupCode } } }
  * topLestSelectComps 和第一个要移动的列表项在同级的组件(处理批量移动的情况),数据结构与compDatas一致
  * nearLowBoundsGroup 将要移动列表项所在的分组的下界,数据结构与compDatas一致
  */
  if (isToplest) {
    //如果移动位置在插入区间的顶部,表明组件在最外层
    topLestSelectComps.forEach((item) => {
      
      result[item] = { newGroup: undefined, oldGroup: compDatas[item].config.groupCode };
      return (compDatas[item].config.groupCode = undefined);
    });

    return result;
  }
  if (nearLowBoundsGroup !== firstCompPrev) {
    //如果移动位置的下界的分组code不等于移动组件的code,则解除或更新分组关系
    topLestSelectComps.forEach((item) => {
      if (item !== nearLowBoundsGroup) {
        result[item] = { newGroup: nearLowBoundsGroup, oldGroup: compDatas[item].config.groupCode };
        compDatas[item].config.groupCode = nearLowBoundsGroup;
      } else {
        result[item] = { newGroup: compDatas[item].config.groupCode, oldGroup: compDatas[item].config.groupCode };
      }
    });
    return result;
  }
  return result;
};

实现

分组子项查询详细代码
    
text

,[object Object],
  
text

,[object Object]