上一篇讲了 HT UI 选用 Canvas 绘制界面的缘由。
这一篇换个视角,聊聊框架的组件储备与底层统一架构:内置组件品类是否充足,组件繁多后如何保持规整,规整之外界面能否完整导出复用。
评判一套绘图工具的功底,不在于能绘制多少元素,而在于万千组件共享同一套底层逻辑。

01 先报个菜单,治一治选择困难
技术选型的第一道难关,往往不是库好不好用,而是组件覆盖是否齐全。
兴冲冲选定一套组件库,开发中途才发现缺少日期选择器、树表格、属性面板,于是开始满世界找第三方组件拼凑、反复踩坑,甚至修改源码 —— 做过项目的人都深有体会。
多方拼凑出的界面会造成交互、视觉标准不统一,页面整体割裂杂乱。
下面摊开 HT UI 组件清单,罗列数十种组件,覆盖绝大多数业务场景:
- 基础控件
按钮、开关、复选框、单选框、文本输入框、文本域、下拉选择器、取色器、日期时间选择器、滑块、进度条、评分组件…… - 数据展示
普通表格、树形表格、纯树形组件、列表、属性面板、网格、时间轴、轮播、标签、步骤条…… - 容器与导航
普通面板、弹窗、抽屉、多标签页、侧边栏、右键菜单、气泡浮窗…… - 布局家族
边框布局、横向 / 纵向布局、网格布局、相对布局、流式布局、多列布局、可拖拽分割面板…… - 高阶组件
内置 Monaco 代码编辑器、文件上传组件、调色面板、消息通知、移动端适配选择器……
下图为基于 HT UI 搭建的可视化 UI 编辑器:按钮、树形控件、数据表格、属性面板、各类布局容器协同运行,全部由框架自有组件构成。
可以重点留意独立划分的布局组件体系,这也是 HT UI 极易被忽略的核心优势。
市面上大部分前端组件库依赖 CSS 完成页面排版,开发者需要手写大量 flex、grid 样式代码。
HT UI 把布局器做成了“独立一等公民”,边框、横纵、网格、相对、流式、分割……每一种布局都拥有完整生命周期,测量、排版、绘制逻辑分层清晰,各司其职。
如果需要开发定制化布局容器,仅需继承基类、重写两个函数,自定义逻辑与业务组件完全复用同一套开发思路。
组件品类已经足够齐全,但品类繁多也会带来新问题:各类组件是各自独立、逻辑割裂,还是共用同一套底层逻辑?这就要讲到 HT UI 真正的内核:DataModel。
02 万物皆 Data:一套模型统全局
整篇系列最核心的观点,希望你能记住:
在 HT 的体系中,界面上所有可见、不可见元素,底层本质都是一份 Data 数据对象。
树形组件的一条节点是 ht.Data,表格的一行数据是 ht.Data,拓扑图上一台机房设备、一条连线,同样是 ht.Data。而统一管理所有 Data 的容器,便是 DataModel(业内常简称为 dm)。
这意味着掌握一套数据操作 API,就能适配几乎全部组件。
向树形组件新增节点、向表格新增行、向列表新增条目,操作逻辑高度统一:
// 以树表格组件举例
var tablePane = new ht.ui.TreeTablePane(),
tableView = tablePane.getTableView(),
dataModel = tableView.dm(); // 获取全局统一数据模型
// 创建数据实例,无需区分组件类型,统一为 ht.Data
var node = new ht.Data();
node.setName('机房 A');
node.a('status', 'online'); // a() 简写存储自定义业务属性,无字段限制
node.a('temperature', 26.5);
dataModel.add(node); // 写入数据模型,绑定组件自动刷新界面
注意看 node.a(‘status’, ‘online’):a() 是 attr 属性的简写,支持随意挂载自定义业务属性,无预设字段约束。
今日存储设备在线状态,明日挂载经纬度,后天记录温湿度,数据模型均可兼容,渲染层按需读取使用即可,无需提前定义字段、修改数据结构。
03 同源联动:一源多显,自动同步
DataModel 最吸引人的特性,是组件间数据联动几乎零开发成本。
同一个 DataModel 实例,可同时绑定多个不同组件:
var dm = new ht.DataModel();
// 左侧树形组件、右侧表格组件,共用同一套数据源
var treeView = new ht.ui.TreeView();
var tableView = new ht.ui.TableView();
treeView.setDataModel(dm);
tableView.setDataModel(dm);
接下来神奇的事发生了:
在左侧树上选中“机房 A”,右侧表格对应行自动同步高亮;从 dm 中删除一条数据,两个组件同步移除对应内容。全程无需手动编写同步代码,只因所有组件读取的是同一份原始数据。
背后是一套朴素却高效的设计理念:界面不存储数据,仅作为数据的可视化镜像。
数据发生变更,视图自动更新;想要修改界面内容,直接操作底层数据即可,无需操作 DOM 或组件实例。
做过多组件联动开发的开发者,一定踩过“修改一处组件,忘记同步其他视图,数据展示不一致”的坑,(看到这句是不是会有点想哭。)但图扑这套机制能从根源规避这类问题。
行业常说 “约定优于配置”,这里也得自嘲一句:
做可视化开发很容易陷入一个误区 —— 为不同组件设计差异化数据格式。树有树的脾气,表有表的规矩,多组件联动需要堆砌大量胶水代码,改一处崩三处。
DataModel 的作用,就是统一全组件数据规范。学会一套 API,所有组件通用。
04 属性页:一次教科书级的示范
如果前面的概念还是略显抽象,那看 PropertyView 属性面板你将会瞬间通透。
这类交互场景十分常见:左侧选中对象,右侧面板自动列出所有可编辑得属性 —— 名字使用文本框、颜色使用拾色器、开关使用开关按钮、数值使用滑块。IDE、可视化设计工具、组态软件、游戏编辑器中随处可见(前文截图右侧面板便是该组件)。
在其他前端框架中,实现该功能需要编写大量绑定逻辑:监听控件变更同步对象、监听对象变更回填控件,双向绑定代码繁琐,来回拉扯极易出现遗漏。
而 HT UI 中,待编辑对象本身就是 ht.Data,属性面板仅需配置属性与编辑器的对应关系:
var propertyView = new ht.ui.PropertyView();
propertyView.setProperties([
{ name: 'name', displayName: '名称', editable: true, editorClass: 'ht.ui.editor.StringEditor' },
{ name: 'status', displayName: '状态', accessType: 'attr',
valueType: 'boolean', editable: true }, // 自动用开关
{ name: 'color', displayName: '颜色', accessType: 'attr',
valueType: 'color', editable: true, editorClass: 'ht.ui.editor.ColorEditor' }
]);
propertyView.dm().add(node); // 把上面那个 ht.Data 丢进来
propertyView.dm().sm().ss(node); // 选中 data 进行显示和编辑
修改面板控件,底层 Data 自动更新;其他业务逻辑修改 Data,面板同步回显最新值 —— 双向绑定、零开发成本,无需手写任何同步逻辑。这便是统一数据模型带来的长期收益:底层规范统一一次,上层所有“数据↔介面”双向交互,自然无缝打通。组件场景越丰富,这份优势越突出。
05 界面也能”打包带走”:序列化
聊完组件丰富度与数据统一性,再介绍一项低调但关键时刻刚需的能力:序列化。
HT UI 支持将整套界面存储成一段 JSON 字符串,后续可通过反序列化一键还原全部界面。
仅一行 API 即可实现,衍生出大量实用场景:
- 可视化编辑器存档
用户在组态工具拖拽搭建界面后,将 JSON 存入数据库;再次打开页面执行反序列化,完整还原布局、数据、滚动位置等全部状态。 - 配置驱动界面
界面布局不再硬编码至代码,而是由 JSON 配置文件控制。修改 JSON 即可调整界面结构,甚至由运营、后台动态下发不同布局配置区分客户,无需前端迭代发版。 - 跨端、多人协作
界面转化为可传输的纯数据,任意环境均可还原相同布局,无需口头描述调整细节。
序列化功能实现顺畅,根源依旧是统一数据模型:所有界面元素均标准化为 Data 对象,转为 JSON 只是基础能力延伸。
底层架构的统一,在这里再次体现价值。这也是前文反复强调 DataModel 的原因:它并非单一独立功能,而是串联组件拓展、多组件联动、界面存档的核心主线。
06 这一篇,请记住三句话
- 组件品类齐全。
数十类基础、高阶组件搭配完整布局器,常规业务无需拼凑第三方组件。 - 万物皆 Data。
依托统一 DataModel 管理全组件数据,一套操作逻辑适配所有组件,多视图联动几乎零成本。 - 界面可完整序列化导出。
一键转为 JSON 存档、动态配置页面、跨端协作都能轻松实现。
组件储备充足、数据流转顺畅、界面支持存档复用,但一套成熟的工具组件库,还需要适配各类使用场景:日间亮色模式、夜间暗色模式、多语言国际化、移动端自适应,全部要兼顾。
下一篇,聊聊组件多样适配能力
且看同一支画笔,如何适配各类场景风格。

