数据模型
Core 接收平铺数组,而不是要求业务方预先构造嵌套树。SDK 根据 ID 和父 ID 建立关系,并把原始业务数据保留在布局结果中。
默认结构
ts
interface Department {
id: string
parentId: string | null
name: string
owner?: string
}一份有效数据应满足:
id是非空且唯一的字符串。- 只有一个节点的
parentId为null,它是根节点。 - 除根节点外,每个
parentId都能找到对应的父节点。 - 父子关系中不存在环。
ts
const data: Department[] = [
{ id: 'root', parentId: null, name: '集团总部' },
{ id: 'tech', parentId: 'root', name: '技术中心', owner: '李明' },
{ id: 'product', parentId: 'root', name: '产品中心' },
]输入校验由业务负责
当前 listToTree() 会选择第一个“父节点不存在”的节点作为根节点,不会主动报告重复 ID、多根、孤立节点或环。建议在接口层完成数据校验,生产数据仍明确使用 parentId: null 表示唯一根节点。
自定义字段映射
业务数据不需要重命名。通过 layout.fieldMap 指定实际字段即可:
ts
const fieldMap = {
id: 'nodeId',
parentId: 'pid',
} as const
const data = [
{ nodeId: 'root', pid: null, label: '总部' },
{ nodeId: 'sales', pid: 'root', label: '销售中心' },
]
const sdk = new OrgTreeCore({
el: '#tree',
layout: {
spaceX: 32,
spaceY: 56,
fieldMap,
},
data,
})FieldMap 还支持可选的 weight 字段,用于向下布局的同级分层:
ts
fieldMap: {
id: 'nodeId',
parentId: 'pid',
weight: 'levelWeight',
}TypeScript 字段推导
DataSource<FM> 可以根据字面量 FieldMap 约束必须存在的 ID 字段:
ts
import type { DataSource } from '@org-tree/core'
type BusinessFieldMap = {
id: 'nodeId'
parentId: 'pid'
}
type BusinessNode = DataSource<BusinessFieldMap>
const node: BusinessNode = {
nodeId: 'root',
pid: null,
label: '总部',
}不传字面量泛型时,DataSource 是允许任意业务字段的宽松对象类型。
布局结果
onUpdate 和 Vue 插槽拿到的节点是 PositionedNode:
ts
interface PositionedNode {
nodeId: string
x: number
y: number
width: number
height: number
info: DataSource
children?: PositionedNode[]
}nodeId:从fieldMap.id对应字段读取。x、y:布局引擎计算的坐标。width、height:nodeSize解析后的尺寸。info:原始业务节点,包含name、owner等所有字段。children:当前参与布局的直接子节点。
不同方向的坐标锚点不同:
| 方向 | x | y |
|---|---|---|
down | 节点水平中心 | 节点顶部 |
right | 节点左边缘 | 节点垂直中心 |
Vue 渲染层已经处理锚点差异。只有自定义渲染器直接使用坐标时才需要关心。
原始 children 字段
业务节点可以包含自己的 children 字段。Core 内部使用 _children 挂载布局关系,避免覆盖业务字段。
不过 listToTree() 会在输入对象上写入内部 _children、width 和 height。如果业务要求输入对象完全不可变,请在调用前创建深拷贝。
数据检查清单
布局异常时依次检查:
- 是否只有一个
parentId: null的根节点 id是否为字符串且没有重复fieldMap是否与接口字段完全一致- 所有非根节点的父 ID 是否存在
- 动态接口返回的子节点
parentId是否等于请求的节点 ID - 是否存在自己指向自己或祖先指向后代的环
nodeSize返回值是否为正数且与卡片尺寸一致