sf-utils2 sf-utils2
版本v3.3.3-beta1
首页
  • 01.快速开始 🔥
  • 02.基础-Base
  • 03.对象-Object
  • 04.数组-Array
  • 05.方法-Function
  • 06.字符串-String
  • 07.数学-Math
  • 08.dom
  • 09.拓展
  • webpack5.x教程学习 (opens new window)
  • 例子
  • 教程 🔥
  • 例子配置
企业级后台模版 (opens new window)
版本v3.3.3-beta1
首页
  • 01.快速开始 🔥
  • 02.基础-Base
  • 03.对象-Object
  • 04.数组-Array
  • 05.方法-Function
  • 06.字符串-String
  • 07.数学-Math
  • 08.dom
  • 09.拓展
  • webpack5.x教程学习 (opens new window)
  • 例子
  • 教程 🔥
  • 例子配置
企业级后台模版 (opens new window)
  • 快速开始

  • 基础-Base

  • 对象-Object

  • 数组-Array✨✨✨

    • 序言 👏
    • uniq 【数组去重】
    • arrayToMap 【数组转成Map】
    • arrayToObj 【数组转成obj】
    • chunk 【数组切割】
    • compact 【去除数组中无效值】
    • remove 【数组中移除一个元素】
    • shuffle 【数组随机打乱】
    • groupBy 【分组】
    • compactIsNoNullable 【去除数组中null/undefined/NaN】
    • arrayDiff【比较数组差异】🔥🔥
    • differenceBy【获取新增数组】🔥
    • intersection 【数组交集】
    • matchSubListGroup
    • listToTree【列表转树形】🔥🔥🔥
      • 1.1 示例
      • 1.2 示例 根据 order 字段进行排序
      • 1.3 示例 根据 callbackList 自定义格式化方法,排序
      • 1.4 示例 根据 callbackList 和 callbackItem 回调函数,输出结果
      • 2.入参说明
        • 主入参
        • props 对象
        • callbackList 回调函数,接收参数
        • callbackItem 回调函数,接收参数
      • 3.源码
    • treeToList【树型转列表】🔥🔥🔥
    • eachTree【遍历树形结构】🔥🔥🔥
    • filterTree【过滤树形结构】🔥🔥🔥
    • childNodesInList【列表中获取某个下所有后代节点】🔥
    • parentNodesInTree【tree中获取所有祖先节点】 🔥
    • formatStrategyIdsInTree【树形数据中只选中父节点】 🔥
    • range 【序号列表生成函数】
  • 方法-Function

  • 字符串-String

  • 数学-Math

  • 文件-Buffer

  • 节点-dom

  • 拓展

  • nodejs

目录

listToTree【列表转树形】🔥🔥🔥

描述

把返回的数据集 list 转换成 Tree(树状结构)常用

# 1.1 示例

import { listToTree } from 'sf-utils2'

const list = [
  { id: 1, name: '香蕉', pId: null },
  { id: 2, name: '苹果', pId: null },
  { id: 3, name: '橘子', pId: null },
  { id: 1001, name: '香蕉A', pId: 1 },
  { id: 1002, name: '香蕉B', pId: 1 },
  { id: 1003, name: '香蕉C', pId: 1 },
  { id: 1004, name: '苹果A', pId: 2 },
  { id: 1005, name: '橘子C', pId: 3 },
  { id: 1006, name: '橘子B', pId: 3 },
  { id: 1007, name: '苹果D', pId: 2 },
  { id: 1008, name: '苹果D', pId: 2 },
  { id: 1009, name: '苹果C', pId: 2 },
  { id: 1010, name: '橘子A', pId: 3 },
  { id: 1001001, name: '香蕉A-儿子', pId: 1001 },
  { id: 1002002, name: '香蕉B-儿子', pId: 1002 },
  { id: 1003003, name: '香蕉C-儿子', pId: 1003 },
  { id: 1004004, name: '苹果A-儿子', pId: 1004 },
  { id: 1005005, name: '橘子C-儿子', pId: 1005 },
  { id: 1006006, name: '橘子B-儿子', pId: 1006 },
  { id: 4, name: '西瓜', pId: null },
  { id: 1011, name: '西瓜A', pId: null },
  { id: 1012, name: '西瓜B', pId: 4 },
  { id: 1013, name: '西瓜B-儿子', pId: 1012 },
  { id: 1001001001, name: '香蕉A-儿子-儿子', pId: 1001001 }
]

// 将list转成树状结构
listToTree({ list: list, root: null, props: { id: 'id', parentId: 'pId', children: 'children' } })
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
输出结果,点击查看
;[
  {
    id: 1,
    name: '香蕉',
    pId: null,
    children: [
      {
        id: 1001,
        name: '香蕉A',
        pId: 1,
        children: [
          {
            id: 1001001,
            name: '香蕉A-儿子',
            pId: 1001,
            children: [
              {
                id: 1001001001,
                name: '香蕉A-儿子-儿子',
                pId: 1001001
              }
            ]
          }
        ]
      },
      {
        id: 1002,
        name: '香蕉B',
        pId: 1,
        children: [
          {
            id: 1002002,
            name: '香蕉B-儿子',
            pId: 1002
          }
        ]
      },
      {
        id: 1003,
        name: '香蕉C',
        pId: 1,
        children: [
          {
            id: 1003003,
            name: '香蕉C-儿子',
            pId: 1003
          }
        ]
      }
    ]
  },
  {
    id: 2,
    name: '苹果',
    pId: null,
    children: [
      {
        id: 1004,
        name: '苹果A',
        pId: 2,
        children: [
          {
            id: 1004004,
            name: '苹果A-儿子',
            pId: 1004
          }
        ]
      },
      {
        id: 1007,
        name: '苹果D',
        pId: 2
      },
      {
        id: 1008,
        name: '苹果D',
        pId: 2
      },
      {
        id: 1009,
        name: '苹果C',
        pId: 2
      }
    ]
  },
  {
    id: 3,
    name: '橘子',
    pId: null,
    children: [
      {
        id: 1005,
        name: '橘子C',
        pId: 3,
        children: [
          {
            id: 1005005,
            name: '橘子C-儿子',
            pId: 1005
          }
        ]
      },
      {
        id: 1006,
        name: '橘子B',
        pId: 3,
        children: [
          {
            id: 1006006,
            name: '橘子B-儿子',
            pId: 1006
          }
        ]
      },
      {
        id: 1010,
        name: '橘子A',
        pId: 3
      }
    ]
  },
  {
    id: 4,
    name: '西瓜',
    pId: null,
    children: [
      {
        id: 1012,
        name: '西瓜B',
        pId: 4,
        children: [
          {
            id: 1013,
            name: '西瓜B-儿子',
            pId: 1012
          }
        ]
      }
    ]
  },
  {
    id: 1011,
    name: '西瓜A',
    pId: null
  }
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

⚠️ 注意

这边在执行listToTree方法时,会默认给每个节点加上 __id__(节点经过路径) 、 __pId__(父节点经过的路径)、__depth__(当前节点深度)、__rootNode__(最上层,根节点对象),__id__ 每一个子节点唯一值,__pId__ 每一个子节点中的父节点值, 你会发现这边的 __id__ 看起来是有规则的,它是下标索引为基值,比如 __id__ 是 0-1-1-1-1 时,表面它处于第 4 层、之前途径的路径是 0-1、0-1-1、 0-1-1-1, 这样方便平时业务中做其他操作,比如要获取每个子节点所有途经的节点集合,我们只需要遍历刚才的 0-1、0-1-1、 0-1-1-1 去 list 中找到 __id__ 是其中之一。是不是感觉很方便?😁
v3.3.0+ 每一个节点都会增加 __prevNode__(当前节点相邻的上一个节点)属性、__nextNode__(当前节点相邻的下一个节点)属性。

// listToTree为每个节点增加属性如下,__depth__、__id__、__level__、__pId__、__rootNode__
// children: (3) [{…}, {…}, {…}]
// id: 1
// name: "香蕉"
// order: 2
// parentId: null
// __depth__: 1  // 当前节点深度
// __id__: "0-1" // 节点经过的路径
// __level__: 1 // 当前节点深度
// __parentNode__: 1 // 当前父节点
// __pId__: "0" // 父节点经过的路径
// __rootNode__: {id: 1, name: '香蕉', parentId: null, order: 2, children: Array(3), …} // 顶层根节点
1
2
3
4
5
6
7
8
9
10
11
12

# 1.2 示例 根据 order 字段进行排序

import { listToTree } from 'sf-utils2'
let list = [
  { id: 1, name: '香蕉', parentId: null, order: 2 },
  { id: 2, name: '苹果', parentId: null, order: 1 },
  { id: 3, name: '橘子', parentId: null, order: 3 },
  { id: 1001, name: '香蕉A', parentId: 1, order: 20 },
  { id: 1002, name: '香蕉B', parentId: 1, order: 2 },
  { id: 1003, name: '香蕉C', parentId: 1, order: 11 },
  { id: 1004, name: '苹果A', parentId: 2, order: 13 },
  { id: 1005, name: '橘子C', parentId: 3 },
  { id: 1006, name: '橘子B', parentId: 3 }
]
// 根据order字段进行排序, sortBy: asc 排序方向  asc:升序  desc:降序
// orderField 排序字段
listToTree({
  list: list,
  root: null,
  props: { id: 'id', parentId: 'parentId', children: 'children', order: true, orderField: 'order' }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

输出结果

# 1.3 示例 根据 callbackList 自定义格式化方法,排序

import { listToTree } from 'sf-utils2'
let list = [
  { id: 1, name: '香蕉', parentId: null, order: 2 },
  { id: 2, name: '苹果', parentId: null, order: 1 },
  { id: 3, name: '橘子', parentId: null, order: 3 },
  { id: 1001, name: '香蕉A', parentId: 1, order: 20 },
  { id: 1002, name: '香蕉B', parentId: 1, order: 2 },
  { id: 1003, name: '香蕉C', parentId: 1, order: 11 },
  { id: 1004, name: '苹果A', parentId: 2, order: 13 },
  { id: 1005, name: '橘子C', parentId: 3 },
  { id: 1006, name: '橘子B', parentId: 3 }
]
// 根据callbackFn自定义格式化方法,排序
listToTree({
  list: list,
  root: null,
  props: { id: 'id', parentId: 'parentId', children: 'children' },
  callbackList: (list, parentObj) => {
    // list:每个节点下子节点数组 parentObj:父节点对象
    console.log('回调函数的值', list, parentObj)
    list.sort((a, b) => a.order - b.order)
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

输出结果

# 1.4 示例 根据 callbackList 和 callbackItem 回调函数,输出结果

import { listToTree } from 'sf-utils2'
let list = [
  { id: 1, name: '香蕉', parentId: null, order: 2 },
  { id: 2, name: '苹果', parentId: null, order: 1 },
  { id: 3, name: '橘子', parentId: null, order: 3 },
  { id: 1001, name: '香蕉A', parentId: 1, order: 20 },
  { id: 1002, name: '香蕉B', parentId: 1, order: 2 },
  { id: 1003, name: '香蕉C', parentId: 1, order: 11 },
  { id: 1004, name: '苹果A', parentId: 2, order: 13 },
  { id: 1005, name: '橘子C', parentId: 3 },
  { id: 1006, name: '橘子B', parentId: 3 }
]
// 根据callbackFn自定义格式化方法,排序
listToTree({
  list: list,
  root: null,
  props: { id: 'id', parentId: 'parentId', children: 'children' },
  callbackList: (list, parentObj) => {
    // list:每个节点下子节点数组 parentObj:父节点对象
    console.log('回调函数的值@callbackList', list, parentObj)
    list.sort((a, b) => a.order - b.order)
  },
  callbackItem: (item, index, list, parentObj) => {
    // item => 当前树节点, index => 当前树节点索引, list => 当前树节点数组, parentObj => 父节点
    console.log('回调函数的值@callbackItem', item, index, list, parentObj)
    // 其中item输出的值是:
    // children: (3) [{…}, {…}, {…}]
    // id: 1
    // name: "香蕉"
    // order: 2
    // parentId: null
    // __depth__: 1  // 当前节点深度
    // __id__: "0-1" // 节点经过的路径
    // __level__: 1 // 当前节点深度
    // __pId__: "0" // 父节点经过的路径
    // __parentNode__: {id: 1, name: '香蕉', parentId: null, order: 2, children: Array(3), …} // 当前父节点
    // __rootNode__: {id: 1, name: '香蕉', parentId: null, order: 2, children: Array(3), …} // 顶层根节点
    return true // 返回true时,表示告诉 listToTree 终止循环,不再调用该callbackItem方法
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

输出结果

# 2.入参说明

# 主入参

参数 说明 类型 是否必填 默认值
list 原数据(要转换的数据集) Array 是
root 根节点值 String
Number
Null
是 0
props 自定义字段键名,详情见下 👇 Object 否
callbackList 每次列表循环回调函数,详情见下 👇 Function 否 null
callbackItem 每次列表每一项回调函数,详情见下 👇 Function 否 null
isDeepClone 是否要深拷贝原 list 对象,默认true Boolean 否 true
retainField 每条数据上要保留的字段 ('__rootNode__', '__pId__', '__level__')[] 否 []

# props 对象

参数 说明 类型 是否必填 默认值
id 自身键名 String 否 id
parentId 父节点键名 String 否 parentId
children 定义children键名 String 否 children
order 是否转化树形时排序 Boolean 否 false
orderField 定义排序键名 String 否 sort
orderBy 定义排序方向键名,可选值
asc(升序) desc(降序)
String 否 asc

# callbackList 回调函数,接收参数

参数 说明 类型 是否必填 默认值
list 当前树节点数组 Array 否
parentObj 父节点对象 Object 否

# callbackItem 回调函数,接收参数

参数 说明 类型 是否必填 默认值
item 当前树节点 Array 否
index 当前树节点索引 Number 否
list 当前树节点数组 Array 否
parentObj 父节点对象 Array 否

# 3.源码

import merge from '../object/merge.js'
import _helperTreeBase, { __callbackItemInterface, __callbackListInterface } from '../_helper/_helperTreeBase.js'
import arrayToObj from '@/array/arrayToObj'

/**
 * @typedef {'__rootNode__', '__pId__', '__level__'} RetainField
 */

/**
 * 把返回的数据集list 转换成 Tree
 * @param list 要转换的数据集
 * @param root 根节点
 * @param {{ id?: 'id', parentId?: 'parentId', children?: 'children', order?: false, orderField?: 'order', orderBy?: 'asc' }} props 映射属性
 * @param {string|'id'|'key'} [props.id]
 * @param {string|'pid'|'parentId'|'pId'} [props.parentId]
 * @param {string|'children'|'child'|'childs'|'childList'} [props.children]
 * @param {boolean} [props.order]
 * @param {string|'order'} [props.orderField]
 * @param {string|'aes'|'desc'|'AES'|'DESC'|'up'|'down'|'UP'|'down'} [props.orderBy] * @param callbackList 回调函数 节点list
 * @param {RetainField[]} retainField 保留的字段
 * @param callbackList
 * @param callbackItem 回调函数 当前节点
 * @param isDeepClone 是否深度克隆
 * @returns {*[]}
 */
function listToTree({
  list = [],
  root = 0,
  props = { id: 'id', parentId: 'parentId', children: 'children', order: false, orderField: 'order', orderBy: 'asc' },
  callbackList = __callbackListInterface,
  callbackItem = __callbackItemInterface,
  retainField = [],
  isDeepClone = true
}) {
  let defProps = {
    id: 'id',
    parentId: 'parentId',
    children: 'children',
    order: false,
    orderField: 'order',
    orderBy: 'asc'
  }
  props = merge({}, defProps, props)

  const _listToTreeFn = ({ list = [], root = 0, props = { id: 'id', parentId: 'parentId', children: 'children' } }) => {
    let _tree = []
    const listToObject = arrayToObj(list, props.id)
    list.forEach(item => {
      if (item[props.parentId] == root) {
        _tree.push(listToObject[item[props.id]])
      } else if (listToObject[item[props.parentId]]) {
        // fix
        if (!listToObject[item[props.parentId]]?.[props.children]) {
          listToObject[item[props.parentId]][props.children] = []
        }
        listToObject[item[props.parentId]][props.children].push(listToObject[item[props.id]])
      }
    })
    return _tree
  }
  let tree = _listToTreeFn({ list, root, props })
  return _helperTreeBase({ props, callbackList, callbackItem, tree, retainField, isDeepClone })
}

export default listToTree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
上次更新: 2025/01/11, 15:37:45
matchSubListGroup
treeToList【树型转列表】🔥🔥🔥

← matchSubListGroup treeToList【树型转列表】🔥🔥🔥→

Theme by Vdoing | Copyright © 2022-2025 bianpengfei
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×