FlexTree
本节之前,我们一直使用FlexTreeManager进行示例讲解。本节开始将介绍一个专注于查询的对象FlexTree。
由于FlexTree基于左右值算法,这是一个查询优先的存储结构,查询效率高,但更新效率低。
所以,原则上,特别适用于查询大于更新的场景,因此为了更好地操作树引入了对象FlexTree和节点对象FlexTreeNode。
创建树对象
FlexTree是一个类,专门用于加载树到内存中,提供更方便的树API。
import type { FlexTreeOptions, IFlexTreeNode } from 'flextree'
import { FlexTreeManager,FlexTree, FlexTreeVerifyError } from 'flextree'
import SqliteAdapter from 'flextree-sqlite-adapter'
const sqliteDriver = new SqliteAdapter()
await sqliteDriver.open()
const tree = new FlexTree('tree', {
adapter: sqliteDriver,
})
await tree.load()对象树
FlexTree对象加载后,会构建一系列由FlexTeeeNode组成的嵌套的对象实例树,如下:
- FlexTreeNodeRoot
- *children[]
- FlexTreeNodeA
- *children[]
- FlexTreeNodeA1
- FlexTreeNodeA2
- FlexTreeNodeA3
- *children[]
- FlexTreeNodeB
- *children[]
- FlexTreeNodeB1
- FlexTreeNodeB2
- FlexTreeNodeB3
- FlexTreeNodeB
- *children[]
- FlexTreeNodeC
- *children[]
- FlexTreeNodeC1
- FlexTreeNodeC2
- FlexTreeNodeC3
- *children[]
- FlexTreeNodeA
- *children[]
泛型
由于FlexTree实例化时内部会自动创建一个FlexTreeManager对象,其泛型与FlexTreeManager一样。
export class FlexTree<
Fields extends Record<string, any> = object,
KeyFields extends CustomTreeKeyFields = DefaultTreeKeyFields
>定制关键字段的方法也一样,如下:
import { FlexTree } from "felxtree"
import PrismaAdapter from "flextree-prisma-adapter"
const tree = new FlexTree<{
size: number
},
{
id:['pk',number],
treeId:['tree',number],
name:"title",
leftValue:'lft',
rightValue:'rgt'
}>('org', {
adapter: new PrismaAdapter(prisma),
fields:{
id:'pk',
treeId:'tree',
name:'title',
leftValue:'lft',
rightValue:"rgt"
}
})可以参考FlexTreeManager介绍。
加载
执行FlexTree.load从数据库中加载树到内存中。
全量加载
const tree = new FlexTree('tree')
console.log(tree.status) // == not-loaded
// 将树一次性加载到内存中
await tree.load()
console.log(tree.status) // == loaded
// 获取根节点FlexNode实例
tree.root懒加载
如果树节点太多,也可以启用懒加载,手动控制节点的加载
const tree = new FlexTree('tree',{
lazy:true
})
await tree.load()以上代码在懒加载模式下,只要加载根节点以及其子节点,对象树如下:
- FlexTreeNodeRoot
- *children[][]
- FlexTreeNodeA
- children[]length=0
- FlexTreeNodeA1未加载
- FlexTreeNodeA2未加载
- FlexTreeNodeA3未加载
- children[]length=0
- FlexTreeNodeB
- children[]length=0
- FlexTreeNodeB1未加载
- FlexTreeNodeB2未加载
- FlexTreeNodeB3未加载
- children[]length=0
- FlexTreeNodeC
- children[]length=0
- FlexTreeNodeC1未加载
- FlexTreeNodeC2未加载
- FlexTreeNodeC3未加载
- children[]length=0
- FlexTreeNodeA
- *children[][]
以上A、B、C三个节点的状态为not-loaded,并且其所有子节点和后代节点均未加载。
然后,接下来您可以按需自行调用FlexTreeNode.load()加载
比如,以下代码将加载B节点:
const bnode = tree.getByPath("Root/B")
console.log(bnode.status) // == 'not-loaded'
await bnode.load()
console.log(bnode.status) // == 'loaded'B节点加载后的对象树:
- FlexTreeNodeRoot
- *children[][]
- FlexTreeNodeA
- children[]length=0
- FlexTreeNodeA1未加载
- FlexTreeNodeA2未加载
- FlexTreeNodeA3未加载
- children[]length=0
- FlexTreeNodeBloaded
- children[]length=3
- FlexTreeNodeB1
- FlexTreeNodeB2
- FlexTreeNodeB3
- children[]length=3
- FlexTreeNodeC
- children[]length=0
- FlexTreeNodeC1未加载
- FlexTreeNodeC2未加载
- FlexTreeNodeC3未加载
- children[]length=0
- FlexTreeNodeA
- *children[][]
提示
FlexTree和FlexTreeNode对象实例均有load方法,FlexTree.load方法用于加载整个树,而FlexTreeNode.load方法仅用于加载指定节点。
根据路径访问节点
当FlexTree或FlexTreeNode加载完毕后,可以通过使用FlexTree和FlexTreeNode对象实例的getByPath来获取指定路径的节点实例。
getByPath(
path: string,
options?: { byField?: string, delimiter?: string }
): FlexTreeNode<Fields, KeyFields, TreeNode, NodeId, TreeId> | undefined- 参数
| 字段名称 | 数据类型 | 描述 |
|---|---|---|
path | string | 节点在树中的位置 |
options | object | 选项 |
options.byField | string | 指定路径是由哪一个字段值组成,默认name |
options.delimiter | string | 路径的分隔符,默认/ |
- 返回值
返回指定路径的FlexTreeNode节点实例,如果节点不存在则返回undefined。
- 示例
tree.getByPath('/')
tree.getByPath('./')
tree.getByPath('./A')
tree.getByPath('./A/A-1')
tree.getByPath('./A/A-1/A-1-1')
tree.getByPath('A')
tree.getByPath('A/A-1')
tree.getByPath('A/A-1/A-1-1')
const b1 = root.getByPath('B')!
b1.getByPath('../A')
b1.getByPath('../A/A-1')
b1.getByPath('../A/A-1/A-1-1')
b1.getByPath('B-1')
b1.getByPath('B-1/B-1-1')说明
FlexTree和FlexTreeNode对象实例均有getByPath方法,FlexTree.getByPath方法用于在整个树检索,而FlexTreeNode.getByPath方法的路径是相对于节点的。- 可以使用相对路径语法,
./表示当前节点,../代表父节点,../../代表祖先节点等。
获取节点
使用FlexTree和FlexTreeNode对象实例的get方法来获取在所在节点及其后代节点中返回指定的实例。
get(nodeId: NodeId): FlexTreeNode<Fields, KeyFields, TreeNode, NodeId, TreeId> | undefined- 参数
| 字段名称 | 数据类型 | 描述 |
|---|---|---|
nodeId | NodeId | 节点的唯一标识 |
- 返回值
返回指定nodeId的FlexTreeNode节点实例,如果节点不存在则返回undefined。
节点状态
当配置FlexTree.options.lazt=true启用懒加载时,FlexTreeNode节点实例具有状态属性,用于表示节点的加载状态。
type FlexTreeNodeStatus = 'not-loaded' | 'loading' | 'loaded' | 'error'- 状态取值
| 状态 | 描述 |
|---|---|
not-loaded | 未加载 |
loading | 加载中 |
loaded | 已加载 |
error | 加载错误 |
同步数据
FlexTree或FlexTreeNode提供sync方法,用于重新从数据库中加载节点数据。
async sync(includeDescendants: boolean = false):voidFlexTree
- 属性
| 方法名称 | 返回类型 | 描述 |
|---|---|---|
root | FlexTreeNode | 返回根节点 |
status | string | 获取树根节点的状态 |
options | FlexTreeOptions | 获取选项 |
manager | FlexTreeManager | 获取管理器 |
- 方法
| 方法名称 | 返回类型 | 描述 |
|---|---|---|
load | Promise<void> | 加载树到内存中 |
getByPath | FlexTreeNode | 根据路径获取节点 |
get | FlexTreeNode | 获取节点 |
find | FlexTreeNode[] | 查找节点 |
toJson | TreeNode | 序列化树为对象 |
toList | TreeNode[] | 序列化树为pid数组 |
on | void | 监听事件 |
off | void | 移除事件监听 |
emit | void | 触发事件 |
sync | void | 同步数据 |
FlexNode
- 属性
| 方法名称 | 返回类型 | 描述 |
|---|---|---|
root | FlexTreeNode | 返回根节点 |
status | string | 获取树根节点的状态 |
options | FlexTreeOptions | 获取选项 |
manager | FlexTreeManager | 获取管理器 |
- 方法
| 方法名称 | 返回类型 | 描述 |
|---|---|---|
load | Promise<void> | 加载树到内存中 |
getByPath | FlexTreeNode | 根据路径获取节点 |
get | FlexTreeNode | 获取节点 |
find | FlexTreeNode[] | 查找节点 |
toJson | TreeNode | 序列化树为对象 |
toList | TreeNode[] | 序列化树为pid数组 |
sync | void | 同步数据 |