02-ClassesBuilder:类型安全的工具类系统
目录
概述
ClassesBuilder 是 Hikari 的工具类生成器,提供了类型安全的 CSS 类名构建方式。它通过枚举驱动的工具类系统,完全替换了传统的字符串拼接方式,实现了编译时类型检查和运行时零开销。
重要提示:ClassesBuilder 和 UtilityClass trait 保留在 hikari-palette 包中,不迁移到 tairitsu-style。这是由于两者设计目标不同导致的架构决策(详见与 Tairitsu 的关系)。
设计理念
核心原则
- 1类型安全 - 编译时检查类名拼写
- 2零运行时开销 - 纯编译时生成
- 3IDE 友好 - 自动补全和跳转
- 4可扩展性 - 模块化组织
架构层次
mermaid
核心架构
1. UtilityClass Trait
定义位置:packages/palette/src/classes/mod.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
职责:
- 定义所有工具类的统一接口
- 自动添加 hi- 前缀
- 支持复合类名(返回多个类)
2. ClassesBuilder 结构
rust
1
2
3
核心方法:
| 方法 | 职责 | 返回值 |
|---|---|---|
| new() | 创建 builder | ClassesBuilder |
| add(class) | 添加单个工具类 | ClassesBuilder |
| add_all(classes) | 批量添加工具类 | ClassesBuilder |
| add_raw(class) | 添加原始类名(无 hi- 前缀) | ClassesBuilder |
| add_if(class, condition) | 条件添加 | ClassesBuilder |
| build() | 构建最终类名字符串 | String |
| as_slice() | 获取类名数组 | &[String] |
3. 工具类分类
布局工具类(Display)
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 输出示例:
// Display::Flex => "hi-flex"
// Display::None => "hi-none"
弹性布局工具类(Flex)
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 输出示例:
// FlexDirection::Col => "hi-flex-col"
// AlignItems::Center => "hi-items-center"
间距工具类(Spacing)
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 输出示例:
// Padding::P4 => "hi-p-4"
// Margin::M2 => "hi-m-2"
尺寸工具类(Sizing)
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 输出示例:
// Width::Full => "hi-w-full"
// Height::Auto => "hi-h-auto"
组件工具类(Components)
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 输出示例:
// Button::ButtonPrimary => "hi-button-primary"
// Card::Card => "hi-card"
工作机制
构建流程
mermaid
类型检查机制
编译时检查:
rust
1
2
3
4
5
6
7
8
9
// no 编译错误:拼写错误
let classes = new
.add // Display 没有 Flx 变体
.build;
// yes 编译通过:IDE 自动补全
let classes = new
.add // IDE 会提示 Flex 变体
.build;
条件添加机制
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
let is_active = true;
let is_disabled = false;
let classes = new
.add
.add_if
.add_if
.add
.build;
// 输出: "hi-flex hi-flex-row hi-button"
// (跳过 hi-flex-row 如果 is_active=false)
// (跳过 hi-button-disabled 如果 is_disabled=false)
扩展机制
添加新工具类
步骤 1:创建枚举
在 packages/palette/src/classes/ 对应模块中添加:
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// packages/palette/src/classes/layout.rs
步骤 2:添加到 mod.rs
rust
1
2
3
4
// packages/palette/src/classes/mod.rs
pub use ;
步骤 3:添加 SCSS 类
scss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// packages/components/src/styles/utilities/overflow.scss
.hi-overflow-auto {
overflow: auto;
}
.hi-overflow-hidden {
overflow: hidden;
}
.hi-overflow-visible {
overflow: visible;
}
.hi-overflow-scroll {
overflow: scroll;
}
步骤 4:使用新工具类
rust
1
2
3
4
5
6
use ;
let classes = new
.add
.build;
// 输出: "hi-overflow-hidden"
复合工具类
某些工具类需要生成多个 CSS 类:
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 使用:
// ClassesBuilder::new().add(Responsive::Md).build()
// 输出: "hi-responsive-md hi-md-block"
性能优化
1. 编译时优化
- 零运行时开销:所有类名在编译时确定
- 字符串预分配:Vec::with_capacity() 预估大小
- 避免克隆:大部分操作使用引用和移动语义
2. 内存优化
rust
1
2
3
4
5
6
3. 批量添加优化
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// yes 推荐:批量添加
let classes = new
.add_all
.build;
// no 避免:多次调用 add
let classes = new
.add
.add
.add
.build;
使用示例
示例 1:基础布局
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use ;
let classes = new
.add
.add
.add
.add
.build;
// 输出: "hi-flex hi-flex-row hi-gap-4 hi-p-4"
// 在 rsx 中使用:
rsx!
示例 2:条件类名
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let is_active = use_signal;
let is_disabled = use_signal;
let button_classes = use_memo;
// is_active=true, is_disabled=false
// 输出: "hi-button hi-button-primary"
// is_active=false, is_disabled=true
// 输出: "hi-button hi-button-disabled"
示例 3:组合多个组件类
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
use ;
use ;
let card_classes = new
.add
.add
.build;
let input_classes = new
.add
.add
.build;
let button_classes = new
.add
.add
.build;
rsx!
示例 4:自定义类名
rust
1
2
3
4
5
6
7
let classes = new
.add
.add_raw // 不添加 hi- 前缀
.add
.build;
// 输出: "hi-flex my-custom-class hi-gap-4"
总结
ClassesBuilder 通过类型安全的工具类系统,实现了:
- 1编译时安全 - 防止类名拼写错误
- 2零运行时开销 - 纯编译时生成
- 3IDE 友好 - 自动补全和类型提示
- 4可扩展性 - 模块化组织,易于添加新工具类
- 5与 SCSS 对应 - 枚举与 .hi-* 类一一对应
这套系统完全替换了传统的字符串拼接方式,是 Hikari 样式体系的基础组件。
与 Tairitsu 的关系
为什么 ClassesBuilder 不迁移到 tairitsu-style?
在 Hikari 到 Tairitsu 构建链迁移(Phase 2)中,我们做出了保留 ClassesBuilder 在 hikari-palette的架构决策。原因如下:
1. 设计目标不同
| 特性 | tairitsu-style | hikari-palette |
|---|---|---|
| 目标 | Tailwind 风格工具类 | Hikari 组件专用类 |
| 命名 | 连字符 (e.g., flex, items-center) | 枚举 (e.g., Display::Flex) |
| 前缀 | 无或可配置 | 固定 hi- 前缀 |
| API | 字符串驱动 | 类型安全枚举 |
2. API 不兼容
rust
1
2
3
4
5
6
7
8
9
// tairitsu-style (Tailwind 风格)
let classes = "flex items-center gap-4";
// hikari-palette (类型安全枚举)
let classes = new
.add
.add
.add
.build;
3. 组件耦合
Hikari 有 18 个组件类枚举文件(Button, Table, Card 等),这些枚举与 hi- 前缀样式系统紧密耦合,迁移成本高且收益低。
4. 架构优势
保留分离的架构提供了:
- 灵活性:Hikari 可以独立演进其类系统
- 类型安全:枚举驱动的系统提供更强的编译时保证
- 组件特化:针对 Hikari 组件优化的类命名
- 兼容性:不破坏现有组件代码
迁移内容
Phase 2 仅迁移了 StyleStringBuilder 和 CssProperty 到 tairitsu-style:
rust
1
2
// hikari-animation/src/style/mod.rs
pub use ;
这提供了:
- 403 个 W3C 标准 CSS 属性
- 统一的属性命名规范
- 减少 635 行重复代码
完整架构
mermaid
最佳实践
使用 ClassesBuilder:
- 静态布局和组件类
- 编译时已知的类名
- 需要类型安全的场景
使用 StyleStringBuilder:
- 动态计算的内联样式
- 需要精确像素值控制的场景
- 覆盖全局样式的场景
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 最佳实践:组合使用
let classes = new
.add
.add
.build;
let style = new
.add_px
.add
.build_clean;
rsx!
更多信息
有关完整迁移详情,请参阅 07-Migration Guide。