数据加载
OrgTreeCore 支持静态数据和动态 API 两种互斥模式。两种模式使用同一套布局、状态和事件 API,区别只在数据从哪里获得。
静态模式
静态模式通过 data 一次传入完整平铺数组:
const sdk = new OrgTreeCore({
el: '#tree',
layout: { spaceX: 32, spaceY: 56 },
data: [
{ id: 'root', parentId: null, name: '总部' },
{ id: 'tech', parentId: 'root', name: '技术中心' },
{ id: 'frontend', parentId: 'tech', name: '前端团队' },
],
})
await sdk.loadData()首次 loadData() 时,全量数据参与布局。SDK 根据完整父子关系精确推导 hasChildren,不需要配置 isLeaf。
调用 collapse({ nodeId }) 会把后代从当前布局列表中移除,但原始静态数据仍保留在内部存储中。下一次 expand() 会从原始数据恢复该节点的直接子节点。
动态模式
动态模式用 api 替代 data:
import type { OrgTreeApi } from '@org-tree/core'
const api: OrgTreeApi = {
async init() {
const response = await fetch('/api/org-tree')
if (!response.ok)
throw new Error(`初始化组织树失败:${response.status}`)
return response.json()
},
async loadChildren(nodeId) {
const response = await fetch(`/api/org-tree/${nodeId}/children`)
if (!response.ok)
throw new Error(`加载 ${nodeId} 的子节点失败:${response.status}`)
return response.json()
},
}
const sdk = new OrgTreeCore({
el: '#tree',
layout: {
spaceX: 32,
spaceY: 56,
isLeaf: node => node.isLeaf === true,
},
api,
})
await sdk.loadData()init() 应返回什么
init() 返回首屏需要展示的平铺节点。通常包含根节点和第一层子节点:
[
{ "id": "root", "parentId": null, "name": "总部", "isLeaf": false },
{ "id": "tech", "parentId": "root", "name": "技术中心", "isLeaf": false },
{ "id": "hr", "parentId": "root", "name": "人力资源", "isLeaf": true }
]如果只返回根节点,根节点会以未展开状态展示;如果同时返回它的子节点,SDK 会根据当前批次推导根节点已展开。
loadChildren(nodeId) 应返回什么
返回指定节点的直接子节点,不要返回整个后代子树:
[
{ "id": "frontend", "parentId": "tech", "name": "前端团队", "isLeaf": true },
{ "id": "backend", "parentId": "tech", "name": "后端团队", "isLeaf": true }
]SDK 会按 ID 去重并把新节点合并到内部存储,然后重新布局。
正确配置 isLeaf
动态模式看不到服务端的完整数据,因此不能根据 parentId 关系判断一个节点是否有孩子。layout.isLeaf 用来把业务字段转换为布尔结果:
layout: {
spaceX: 32,
spaceY: 56,
isLeaf: node => node.childCount === 0,
}不配置时采用保守策略:所有动态节点都可能有子节点,因此都会显示展开按钮。
在接口中返回叶子标记
推荐让初始化接口和子节点接口都返回 isLeaf 或 childCount。这比前端根据节点类型猜测更可靠。
加载时序
loadData()
├─ 静态:读取 config.data
└─ 动态:等待 api.init()
↓
初始化节点状态
↓
计算布局
↓
onUpdate(nodes, Init)
↓
onStatusChange(diff)展开节点时,SDK 会先把该节点设为 loading: true,等待数据返回后合并节点、更新状态并触发 UpdateType.Expand。
错误处理
loadData() 和 expand() 都返回 Promise。主动调用时应捕获错误并反馈给用户:
try {
await sdk.loadData()
}
catch (error) {
console.error('[OrgTree] 初始化失败', error)
}当前内置展开按钮会直接调用 sdk.expand()。因此动态 API 应在请求层统一处理鉴权、超时、重试和错误上报,避免把不可恢复的响应直接交给布局层。
如果接口成本较高,可在 loadChildren 外部按 nodeId 添加缓存。当前 SDK 会对合并结果去重,但收起后再次展开仍会调用一次 loadChildren()。