Skip to content

Commit

Permalink
feat: add treeTrace()
Browse files Browse the repository at this point in the history
  • Loading branch information
axolo committed Nov 5, 2024
1 parent dd9cdfd commit f1d5209
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 34 deletions.
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,20 @@ const tree = array2tree(tree2array([/* tree */]))

## api

| function | return | description |
| ----------------------------------------- | ------ | ------------------------------------------------------------------- |
| `randomId(prefix = '')` | string | generate random id with prefix, like `i_9fang05da21` |
| `array2tree(array, [options])` | array | array to tree with leaf and deep |
| `arrayTrace(array, id, [options])` | array | trace source of id from array |
| `arrayDeep(array, [options], [deep = 1])` | int | get max deep of array |
| `arrayNode(array, id, [options])` | array | get path of id from array by id, like `[id1, id12, id121]` |
| `tree2array(tree, [options])` | array | tree to array and generate id, parentId and leaf when undefined |
| `treeFilter(tree, condition, [options])` | array | get new tree filter by condition function like `node => !node.hide` |
| `treeDeep(tree, [options], [deep = 1])` | int | get max deep of tree |
| `treeNode(tree, id, [options])` | array | get path of id from tree by id, like `[id1, id12, id121]` |
| `treePath(tree, id, [options])` | array | get path of index from tree by id, like `[0, 2, 1]` |
| `treeSub(tree, id, [options])` | object | get sub tree by id, like `{ id, parentId, children: [] }` |
| function | return | description |
| ----------------------------------------- | ------ | --------------------------------------------------------------------------------- |
| `randomId(prefix = '')` | string | generate random id with prefix, like `i_9fang05da21` |
| `array2tree(array, [options])` | array | array to tree with leaf and deep |
| `arrayDeep(array, [options], [deep = 1])` | int | get max deep of array |
| `arrayTrace(array, id, [options])` | array | trace source of node by id from array, like `[object1, object12, object121]` |
| `arrayNode(array, id, [options])` | array | get path of id from array by id, like `[id1, id12, id121]` |
| `tree2array(tree, [options])` | array | tree to array and generate id, parentId and leaf when undefined |
| `treeDeep(tree, [options], [deep = 1])` | int | get max deep of tree |
| `treeFilter(tree, condition, [options])` | array | get new tree filter by condition function like `node => !node.hide` |
| `treePath(tree, id, [options])` | array | get path of index from tree by id, like `[0, 2, 1]` |
| `treeNode(tree, id, [options])` | array | get path of id from tree by id, like `[id1, id12, id121]` |
| `treeTrace(tree, id, [options])` | array | get path of node as object from tree by id, like `[object1, object12, object121]` |
| `treeSub(tree, id, [options])` | object | get sub tree by id, like `{ id, parentId, children: [] }` |

## options

Expand Down
1 change: 1 addition & 0 deletions docs/.vitepress/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default {
{ text: 'tree2array', link: '/tree2array' },
{ text: 'treeDeep', link: '/treeDeep' },
{ text: 'treeNode', link: '/treeNode' },
{ text: 'treeTrace', link: '/treeTrace' },
{ text: 'treePath', link: '/treePath' },
{ text: 'treeFilter', link: '/treeFilter' },
{ text: 'treeSub', link: '/treeSub' }
Expand Down
2 changes: 1 addition & 1 deletion docs/arrayNode.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 列表溯源节点
# 列表溯源主键

```js
arrayNode(array, id, [options])
Expand Down
2 changes: 1 addition & 1 deletion docs/arrayTrace.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 列表溯源
# 列表溯源对象

```js
arrayTrace(array, id, [options])
Expand Down
2 changes: 1 addition & 1 deletion docs/treeNode.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 树溯源节点
# 树溯源主键

```js
treeNode(tree, id, [options])
Expand Down
126 changes: 126 additions & 0 deletions docs/treeTrace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# 树溯源对象

```js
treeTrace(tree, id, [options])
```

根据主键的值从树中溯源,返回**从根到自身**顺序的对象数组,如:`[object1, object12, object121]`

## 参数

| 参数 | 类型 | 默认 | 说明 |
| --------- | -------- | ---- | -------------------------------------------------- |
| `tree` | `array` | | [树状结构数据](./param.md#tree) |
| `id` | `any` | | [主键](./param.md#id)的值,如:`chartProjectMyTwo` |
| `options` | `object` | | [配置选项](./param.md#options) |

## 返回

| 参数 | 类型 | 说明 |
| ---- | ------- | ---------------------------- |
| * | `array` | 从根到自身顺序溯源的对象数组 |

## 示例

::: code-group
```js [调用]
import { treeTrace } from '@axolo/tree-array'

const tree = [{
id: 'home',
path: '/home',
parentId: null
}, {
id: 'chart',
path: '/chart',
parentId: null,
children: [{
id: 'chartIndex',
path: '/chart/index',
parentId: 'chart',
children: [{
id: 'chartIndexTop',
path: '/chart/index/top',
parentId: 'chartIndex'
}, {
id: 'chartIndexActive',
path: '/chart/index/active',
parentId: 'chartIndex',
children: [{
id: 'chartIndexActiveMy',
path: '/chart/index/active/my',
parentId: 'chartIndexActive'
}]
}]
}, {
id: 'chartReview',
path: '/chart/review',
parentId: 'chart'
}, {
id: 'chartProject',
path: '/chart/project',
parentId: 'chart',
children: [{
id: 'chartProjectYou',
path: '/chart/project/you',
parentId: 'chartProject',
test: true
}, {
id: 'chartProjectMy',
path: '/chart/project/my',
parentId: 'chartProject',
children: [{
id: 'chartProjectMyOne',
path: '/chart/project/my/one',
parentId: 'chartProjectMy'
}, {
id: 'chartProjectMyTwo',
path: '/chart/project/my/two',
parentId: 'chartProjectMy'
}]
}]
}]
}, {
id: 'smile',
path: '/smile',
parentId: null,
children: [{
id: 'smileIndex',
path: '/smile/index',
parentId: 'smile',
test: true
}]
}]

treeTrace(tree, 'chartProjectMyTwo') // array of id
```

```json [结果]
[
{
"id": "chart",
"path": "/chart",
"parentId": null,
"children": null
},
{
"id": "chartProject",
"path": "/chart/project",
"parentId": "chart",
"children": null
},
{
"id": "chartProjectMy",
"path": "/chart/project/my",
"parentId": "chartProject",
"children": null
},
{
"id": "chartProjectMyTwo",
"path": "/chart/project/my/two",
"parentId": "chartProjectMy",
"children": null
}
]
```
:::
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@axolo/tree-array",
"version": "0.5.4",
"version": "0.6.0",
"description": "An array have children key and parentId key like tree.",
"author": "Yueming Fang",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion src/lib/array-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const arrayNode = (array, id, options, parents = []) => {
options = { ...config, ...options }
const { idKey, parentKey } = options
const item = array.find(a => a[idKey] === id)
if (!item || !item[idKey]) return parents
if (!item?.[idKey]) return parents
parents.unshift(item[idKey]) // only id
return arrayNode(array, item[parentKey], options, parents)
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/array-trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const arrayTrace = (array, id, options, parents = []) => {
options = { ...config, ...options }
const { idKey, parentKey } = options
const item = array.find(a => a[idKey] === id)
if (!item || !item[idKey]) return parents
if (!item?.[idKey]) return parents
parents.unshift(item)
return arrayTrace(array, item[parentKey], options, parents)
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import treeFilter from './tree-filter'
import treeDeep from './tree-deep'
import treeNode from './tree-node'
import treePath from './tree-path'
import treeTrace from './tree-trace'
import treeSub from './tree-sub'

export {
Expand All @@ -23,5 +24,6 @@ export {
treeDeep,
treeNode,
treePath,
treeTrace,
treeSub
}
10 changes: 5 additions & 5 deletions src/lib/tree-node.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import config from './config'

const treeNode = (tree, targetId, options, currentPath = []) => {
const treeNode = (tree, id, options, currentNode = []) => {
options = { ...config, ...options }
const { idKey, childrenKey } = options

for (let node of tree) {
currentPath.push(node[idKey]) // 将当前节点ID加入路径
if (node[idKey] === targetId) return currentPath // 找到目标ID,返回路径
currentNode.push(node[idKey]) // 将当前节点ID加入路径
if (node[idKey] === id) return currentNode // 找到目标ID,返回路径
if (node[childrenKey]) {
const result = treeNode(node[childrenKey], targetId, options, currentPath) // 递归遍历子节点
const result = treeNode(node[childrenKey], id, options, currentNode) // 递归遍历子节点
if (result) return result // 找到目标ID,返回路径
}
currentPath.pop() // 回溯,将当前节点ID从路径中移除
currentNode.pop() // 回溯,将当前节点ID从路径中移除
}
return null // 遍历完所有节点,未找到目标ID,返回null
}
Expand Down
6 changes: 3 additions & 3 deletions src/lib/tree-path.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import config from './config'

const treePath = (tree, targetId, options, currentPath = []) => {
const treePath = (tree, id, options, currentPath = []) => {
options = { ...config, ...options }
const { idKey, childrenKey } = options

for (let i = 0; i < tree.length; i++) {
currentPath.push(i) // 将当前节点索引号加入路径
if (tree[i][idKey] === targetId) return currentPath // 找到目标ID,返回路径
if (tree[i][idKey] === id) return currentPath // 找到目标ID,返回路径
if (tree[i][childrenKey]) {
const result = treePath(tree[i][childrenKey], targetId, options, currentPath) // 递归遍历子节点
const result = treePath(tree[i][childrenKey], id, options, currentPath) // 递归遍历子节点
if (result) return result // 找到目标ID,返回路径
}
currentPath.pop() // 回溯,将当前节点索引号从路径中移除
Expand Down
10 changes: 5 additions & 5 deletions src/lib/tree-sub.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ const treeSub = (tree, id, options) => {
options = { ...config, ...options }
const { idKey, childrenKey } = options

for (let i = 0; i < tree.length; i++) {
if (tree[i][idKey] === id) {
return tree[i]
} else if (tree[i][childrenKey] && tree[i][childrenKey].length > 0) {
const result = treeSub(tree[i][childrenKey], id, options)
for (const node of tree) {
if (node[idKey] === id) {
return node
} else if (node[childrenKey] && node[childrenKey].length > 0) {
const result = treeSub(node[childrenKey], id, options)
if (result) {
return result
}
Expand Down
19 changes: 19 additions & 0 deletions src/lib/tree-trace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import config from './config'

const treeTrace = (tree, id, options, currentTrace = []) => {
options = { ...config, ...options }
const { idKey, childrenKey } = options

for (const node of tree) {
currentTrace.push({ ...node, [childrenKey]: null }) // 将当前节点加入路径
if (node[idKey] === id) return currentTrace // 找到目标ID,返回路径
if (node[childrenKey]) {
const result = treeTrace(node[childrenKey], id, options, currentTrace) // 递归遍历子节点
if (result) return result // 找到目标ID,返回路径
}
currentTrace.pop() // 回溯,将当前节点从路径中移除
}
return null // 遍历完所有节点,未找到目标ID,返回null
}

export default treeTrace
6 changes: 4 additions & 2 deletions src/test/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import {
array2tree,
arrayParents,
arrayNode,
arrayTrace,
arrayDeep,
tree2array,
treeFilter,
treeSub,
treeNode,
treePath,
treeDeep,
arrayTrace
treeTrace,
treeDeep
} from '../lib'
export default {
Expand All @@ -42,6 +43,7 @@ export default {
{ name: 'treeSub', result: treeSub(tree, 'chartIndexActive') },
{ name: 'treeNode', result: treeNode(tree, 'chartProjectMyTwo') },
{ name: 'treePath', result: treePath(tree, 'chartProjectMyTwo') },
{ name: 'treeTrace', result: treeTrace(tree, 'chartProjectMyTwo') },
{ name: 'treeDeep', result: treeDeep(tree) },
{ name: 'tree2array2tree', result: array2tree(tree2array(cloneDeep(tree))) }
]
Expand Down

0 comments on commit f1d5209

Please sign in to comment.