架构思路
这套组件库只做一件事:在 ice-render 的图形能力之上,搭一层「UI 组件」的约定与基础设施,
让写界面的人不用关心 canvas 的坐标、命中检测、重绘时机。
理解下面这几条,基本就理解了整个库:
- 组件不是 DOM:每个组件都是画布上的一棵子树,位置是
state.left/top,样式是state.style; - 引擎管渲染,组件管语义:脏矩形、zIndex、裁剪、离屏缓存都是引擎的事;组件只负责“长什么样、怎么响应”;
- 一切跨组件的交互都收敛到四个管理器:浮层、焦点、悬停、消息 —— 组件不自己造轮子;
- 约定优于配置:表单取值、状态色、节流/关闭策略、主题 token 都有统一约定,新增组件照着抄即可。
一、分层
两条硬边界:
- 组件库不碰 canvas 的绘制原语(不直接
ctx.fillRect)——需要画什么就组合引擎图元; 只有少数需要特殊路径的组件(ICESpin的圆弧、ICEProgressBar的环形、ICESvgIcon的 SVG 路径) 才通过继承ICEPath自定义createPathObject()。 - 引擎不知道 UI 语义(不知道什么是表单、浮层、焦点)——这些东西全部在组件库里实现。
二、组件模型
ICEWidget 是所有 UI 组件的基类(继承引擎的 ICEGroup),只加了四件事:
| 能力 | 说明 |
|---|---|
enabled / hovered / focused | 交互态;对应 __applyHoverState() / __applyFocusState() 钩子 |
focusable / activate() | 参与 Tab 轮转;activate() 默认等价一次 click,控件可覆盖(开关就覆盖成“切换”) |
validateStatus | 表单错误态;__applyValidateState() 钩子是画红框的地方 |
getFormValue() / setFormValue() | 表单取值约定;UIFormItem 只认这两个方法 |
再加一条很关键的约定:组件构造函数结束时必须已经是“画好的”状态。
没有延迟到首次渲染才建子节点的写法 —— 这样 measure()(例如示例页的流式布局)在构造后就能拿到真实包围盒。
生命周期只有两个钩子:
protected afterAddHandler() // 组件挂进 ICE 场景后调用:在这里订阅 evtBus、绑定全局事件
protected __applyValidateState() // …
继承骨架(classDiagram)
内置组件分两条技术路线:
- 画布组件:
ICEWidget ← ICEContainer ← …与ICEPath ← …两条,最终落在引擎图元(ICEGroup/ICEPath)上,是真正的画布子树;- 浮层包装类:
ICEPopover/ICEPopconfirm不是ICEWidget,只负责在ICEOverlayManager之上编排浮层的定位 / 关闭 / 动画。