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):void
FlexTree
- 属性
方法名称 | 返回类型 | 描述 |
---|---|---|
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 | 同步数据 |