LayoutBox 布局模型
布局模型的核心是:组件外面永远有一层 SDK 管的盒子,组件自己只管盒子里面怎么画。
四层字段
| 字段 | 含义 | 谁消费 |
|---|---|---|
PageDocument.layout.canvas | 画布如何放进宿主容器 | Renderer / Designer |
PageInstance.layoutBox | 实例自己的外层盒子 | SDK wrapper |
PageInstance.layoutItem | 实例作为父布局子项时的位置规则 | 父容器布局 |
PageInstance.containerLayout | 实例作为容器时,它内部怎么排子组件 | Renderer / reference 容器 |
layoutBox
ts
interface LayoutBox {
x: number
y: number
width: number
height: number
widthMode: 'px' | 'percent' | 'fill' | 'auto'
heightMode: 'px' | 'percent' | 'fill' | 'auto'
overflow?: 'hidden' | 'visible' | 'auto'
}单位语义:
| mode | 意思 | 典型场景 |
|---|---|---|
px | 固定像素 | 画布上自由摆放的卡片 |
percent | 相对父盒子的百分比 | 容器内宽 100% |
fill | 撑满父可用空间 | 运行态卡片填满业务容器 |
auto | 由内容决定 | 文本、标签、小按钮 |
containerLayout
容器内部布局有几种模式:
| mode | 用法 |
|---|---|
free | 容器内还能自由拖,子实例 layoutBox.x/y 相对父 outlet |
flex | 类 CSS flex,适合横排/竖排/换行 |
grid | 类 CSS grid,适合二维卡片网格 |
split | 按比例切分区域,适合左右/上下拆分 |
free-split | 容器内任意分割树(递归切左右/上下),每格一个组件;可视化切分 / 合并 / resize / 删除 / 移动交换(0.5.0+) |
free-split与其它模式有两点不同:渲染 data-driven(页面文档里有 free-split 就自动按树渲染,宿主零 opt-in;非 free-split 页零变化)、编辑受 gate(设计器要传:free-split-enabled="true"才能编辑)。详见 自由分割布局(free-split)。
为什么不直接让组件自己写宽高
因为组件源码属于组件库,而页面里的实例属于页面文档。两者必须分层:
- 组件源码决定内部结构和默认样式。
layoutBox决定这个实例在页面里占多大、放哪儿、如何裁剪。
这样同一个组件能在多个页面、多个容器里复用。
画布和宿主容器
运行态推荐让宿主容器决定真实宽高:
vue
<section class="h-[520px]">
<HyperCardPageRenderer :payload="payload" canvas-id="card-a" />
</section>页面文档里画布可以是 fill。设计态可以模拟宿主容器尺寸,运行态则由真实业务容器接管。
当前不做什么
- 不做完整 CSS Grid 可视化编辑器。
- 不做业务布局模板市场。
- 不自动推断组件内部 DOM 的语义。
- 不把 padding/margin 放进 SDK 盒模型;这类一般是组件 props 或组件 CSS。
进一步阅读
- 如何写一个布局组件 — flex / split / grid / free 最小可用源码 + 自定义布局组件
- 自由分割布局(free-split) — 0.5.0 新增:递归分割树容器 + 宿主接入(渲染/编辑/后端/drop)