Skip to content

FlexTree

本节之前,我们一直使用FlexTreeManager进行示例讲解。本节开始将介绍一个专注于查询的对象FlexTree

由于FlexTree基于左右值算法,这是一个查询优先的存储结构,查询效率高,但更新效率低。 所以,原则上,特别适用于查询大于更新的场景,因此为了更好地操作树引入了对象FlexTree和节点对象FlexTreeNode

创建树对象

FlexTree是一个类,专门用于加载树到内存中,提供更方便的树API

ts
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
      • FlexTreeNodeB
        • *children[]
          • FlexTreeNodeB1
          • FlexTreeNodeB2
          • FlexTreeNodeB3
          • FlexTreeNodeB
      • FlexTreeNodeC
        • *children[]
          • FlexTreeNodeC1
          • FlexTreeNodeC2
          • FlexTreeNodeC3

泛型

由于FlexTree实例化时内部会自动创建一个FlexTreeManager对象,其泛型与FlexTreeManager一样。

ts
export class FlexTree<
    Fields extends Record<string, any> = object,
    KeyFields extends CustomTreeKeyFields = DefaultTreeKeyFields
>

定制关键字段的方法也一样,如下:

ts
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从数据库中加载树到内存中。

全量加载

ts
const tree = new FlexTree('tree')

console.log(tree.status)  // == not-loaded
// 将树一次性加载到内存中
await tree.load()
console.log(tree.status)  // ==  loaded
// 获取根节点FlexNode实例
tree.root

懒加载

如果树节点太多,也可以启用懒加载,手动控制节点的加载

ts
const tree = new FlexTree('tree',{
    lazy:true
})
 
await tree.load()

以上代码在懒加载模式下,只要加载根节点以及其子节点,对象树如下:

  • FlexTreeNodeRoot
    • *children[][]
      • FlexTreeNodeA
        • children[]length=0
          • FlexTreeNodeA1未加载
          • FlexTreeNodeA2未加载
          • FlexTreeNodeA3未加载
      • FlexTreeNodeB
        • children[]length=0
          • FlexTreeNodeB1未加载
          • FlexTreeNodeB2未加载
          • FlexTreeNodeB3未加载
      • FlexTreeNodeC
        • children[]length=0
          • FlexTreeNodeC1未加载
          • FlexTreeNodeC2未加载
          • FlexTreeNodeC3未加载

以上ABC三个节点的状态为not-loaded,并且其所有子节点和后代节点均未加载。

然后,接下来您可以按需自行调用FlexTreeNode.load()加载

比如,以下代码将加载B节点:

ts
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未加载
      • FlexTreeNodeBloaded
        • children[]length=3
          • FlexTreeNodeB1
          • FlexTreeNodeB2
          • FlexTreeNodeB3
      • FlexTreeNodeC
        • children[]length=0
          • FlexTreeNodeC1未加载
          • FlexTreeNodeC2未加载
          • FlexTreeNodeC3未加载

提示

FlexTreeFlexTreeNode对象实例均有load方法,FlexTree.load方法用于加载整个树,而FlexTreeNode.load方法仅用于加载指定节点。

根据路径访问节点

FlexTreeFlexTreeNode加载完毕后,可以通过使用FlexTreeFlexTreeNode对象实例的getByPath来获取指定路径的节点实例。

ts
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

  • 示例
ts
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')
  • 说明

    • FlexTreeFlexTreeNode对象实例均有getByPath方法,FlexTree.getByPath方法用于在整个树检索,而FlexTreeNode.getByPath方法的路径是相对于节点的。
    • 可以使用相对路径语法,./表示当前节点,../代表父节点,../../代表祖先节点等。

获取节点

使用FlexTreeFlexTreeNode对象实例的get方法来获取在所在节点及其后代节点中返回指定的实例。

ts
get(nodeId: NodeId): FlexTreeNode<Fields, KeyFields, TreeNode, NodeId, TreeId> | undefined
  • 参数
字段名称 数据类型 描述
nodeId NodeId 节点的唯一标识
  • 返回值

返回指定nodeIdFlexTreeNode节点实例,如果节点不存在则返回undefined

节点状态

当配置FlexTree.options.lazt=true启用懒加载时,FlexTreeNode节点实例具有状态属性,用于表示节点的加载状态。

ts
type FlexTreeNodeStatus = 'not-loaded' | 'loading' | 'loaded' | 'error'
  • 状态取值
状态 描述
not-loaded 未加载
loading 加载中
loaded 已加载
error 加载错误

同步数据

FlexTreeFlexTreeNode提供sync方法,用于重新从数据库中加载节点数据。

ts
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 同步数据