JS将“/”分割的字符串与树形结构相互转换

133 阅读1分钟
  `一级选项 1/二级选项 1/三级选项 1
一级选项 1/二级选项 1/三级选项 2
一级选项 2/二级选项 1`
 
//相互转换
 
[
  {
    label: '一级选项 1',
    value: '一级选项 1',
    children: [
      {
        label: '二级选项 1',
        value: '二级选项 1',
        children: [
          {
            label: '三级选项 1',
            value: '三级选项 1',
          },
          {
            label: '三级选项 2',
            value: '三级选项 2',
          },
        ],
      },
    ],
  },
  {
    label: '一级选项 2',
    value: '一级选项 2',
    children: [
      {
        label: '二级选项 1',
        value: '二级选项 1',
      },
    ],
  },
]

/**
 * 字符串分割转为树结构
 * @param {String} str
 */
export function str2tree(str) {
  const menuObj = {};
  let arr = [];
  [...new Set(str.split('\n'))].forEach((text) => {
    const itemArr = text.split('/').map(e => e.trim()).filter(e => e);
    arr.push(...itemArr.map((e, i) => ({ label: e, value: e, pLabel: itemArr[i - 1] })))
  })
  arr = [...new Set(arr.map(e => JSON.stringify(e)))].map(e => JSON.parse(e))
  arr.forEach(item => {
    item.children = [];
    menuObj[item.label] = item;
  });
  arr = arr.filter(item => {
    const childList = menuObj[item?.pLabel]?.children;
    if (childList) childList.push(item);
    return !('pLabel' in item)
  })
  return forEachTree(arr, (e) => {
    delete e.pLabel;
    if (!e.children?.length) delete e.children
  });
}
/**
 * 循环树
 * @param {Array} tree 
 * @param {Function} callback 
 */
function forEachTree(tree, callback) {
  tree?.forEach(item => {
    callback(item)
    forEachTree(item.children, callback)
  })
  return tree
}

/**
 * 树结构转为字符串分割
 * @param {Array} arr
 * @returns 
 */
export function tree2str(arr) {
  const strArr = []
  const tree = JSON.parse(JSON.stringify(arr));
  forEachTreeHasParent(tree, undefined, (parent, item) => {
    item.pLabel = `${(parent?.pLabel ?? '')}/${(parent?.label ?? '')}`
    if (parent && !item?.children?.length) {
      strArr.push(`${item.pLabel}/${item.label}`.split('/').filter(e => e).join('/'))
    }
  })
  return strArr.join('\n')
}
/**
 * 循环树
 * @param {Array} tree 
 * @param {Object} parent 
 * @param {Function} callback 
 */
function forEachTreeHasParent(tree, parent, callback) {
  tree?.forEach(item => {
    callback(parent, item)
    forEachTreeHasParent(item.children, item, callback)
  })
  return tree
}