前端JS中常用的处理树型结构的常用工具函数
使⽤了lodash的深拷贝⽅法
import { cloneDeep } from 'lodash-es'
/**
* 遍历 tree
* @param {object[]} tree
* @param {function} cb - 回调函数
* @param {string} children - ⼦节点 字段名
* @param {string} mode - 遍历模式,DFS:深度优先遍历 BFS:⼴度优先遍历 * @return {void} Do not return anything */
export function treeForEach(tree: any[], cb: (item: any) => unknown, children = 'children', mode = 'DFS'): void { if (!Array.isArray(tree)) {
throw new TypeError('tree is not an array') }
if (typeof children !== 'string') {
throw new TypeError('children is not a string') }
if (children === '') {
throw new Error('children is not a valid string') }
// 深度优先遍历 depth first search function DFS(treeData: any[]) { // eslint-disable-next-line for (const item of treeData) { cb(item)
if (Array.isArray(item[children])) { DFS(item[children]) } } }
// ⼴度优先遍历 breadth first search function BFS(treeData: any[]) { const queen = treeData while (queen.length > 0) { const item = queen.shift() cb(item)
if (Array.isArray(item[children])) { queen.push(...item[children]) } } }
if (mode === 'BFS') { BFS(tree) } else { DFS(tree) }}
/**
* tree 转 数组
* @param {object[]} tree
* @param {string} children - ⼦节点 字段名
* @param {string} mode - 遍历模式,DFS:深度优先遍历 BFS:⼴度优先遍历 * @return {array} */
export function treeToList(tree: Array throw new TypeError('tree is not an array') } if (typeof children !== 'string') { throw new TypeError('children is not a string') } if (children === '') { throw new Error('children is not a valid string') } tree = cloneDeep(tree) const list: any = [] treeForEach(tree, (item : any) => { list.push(item) }, children, mode) list.forEach((item: any) => { delete item[children] // 会改变 原数据 }) return list} /** * 数组 转 tree * @param {object[]} list * @param {object} options * @param {string|number|null|undefined} options.rootID - 根节点ID * @param {string|number} options.id - 唯⼀标识 字段名 * @param {string|number} options.pid - ⽗节点ID 字段名 * @param {string} options.children - ⼦节点 字段名 * @return {array} */ interface Options { rootID?: string, id?: string, pid?: string, children?: string} export function listToTree(list: any[], options:Options): Array rootID = null, // 根节点ID,pid === rootID 即为 ⼀级节点 id = 'id', // 唯⼀标识 pid = 'pid', // ⽗节点ID 字段 children = 'children' // ⼦节点 字段 } = options || {} if (!Array.isArray(list)) { throw new TypeError('list is not an array') } if (typeof children !== 'string') { throw new TypeError('children is not a string') } if (children === '') { throw new Error('children is not a valid string') } list = cloneDeep(list) const tree: any = [] const map = list.reduce((res, item) => { res.set(item[id], item) return res }, new Map()) Array.from(map.keys()).forEach(key => { const node = map.get(key) if (node[pid] === rootID) { // ⼀级节点,直接添加到 tree tree.push(node) } else { // ⾮⼀级节点,查找⽗级,并添加到⽗级 children 中 const pNode = map.get(node[pid]) if (Array.isArray(pNode[children])) { pNode[children].push(node) } else { pNode[children] = [node] } } }) return tree} 因篇幅问题不能全部显示,请点此查看更多更全内容