组件与区块 Components vs Blocks
理解组件与区块之间的区别。
构建块谱系
并不是所有东西都适合放进设计系统库。Kumo 区分组件(共享的、有版本的原语) 和区块(你复制并据为己有的模式)。理解这一区别,能帮助你在保持恰当所有权层级的同时更快地构建应用。
这不只是组织偏好问题——它关乎职责。组件是我们维护、测试并管理版本的原语。区块则是有用的起点,由你扩展和改造以满足自身需求。
组件
组件是原子级、可复用的 UI 元素,构成你应用的基础。Button、Input、Dialog、Badge——这些是内容无关、上下文无关的构建块,为在任何产品中最大化复用而设计。
特点
- 有版本且持续维护 —— API 由我们负责,修复缺陷并发布更新
- 支持树摇 (tree-shaking) —— 只导入你用到的部分,没有冗余
- 默认无障碍 —— 基于 Base UI 原语构建,具备完善的 ARIA 支持
- 符合设计系统规范 —— 语义令牌、一致的变体、可预期的 API
- 无预设假设 —— 不含业务逻辑,不预设任何产品场景
用法
直接从包中导入:
import { Button, Input, Dialog, Badge } from "@cloudflare/kumo";
// 也可以使用细粒度导入以获得更好的树摇效果
import { Button } from "@cloudflare/kumo/components/button";
当 Kumo 发布新版本时,你会自动获得缺陷修复和改进。你的代码无需改动——只需升级版本号。
区块
区块是组件的组合,用于解决常见模式,但通用性不足以进入核心库。PageHeader、ResourceList——这些是有价值的、可复用的模式,但它们可能只适用于某些产品,或需要针对具体产品做定制。
特点
- 归你所有 —— 代码位于你的项目中,实现由你掌控
- 完全可定制 —— 可以修改属性 (props) 允许范围之外的任何内容
- 组合优先 —— 由 Kumo 组件构建,而非原始 HTML
- 是起点而非限制 —— 是可扩展的模式,不是需要绕开的约束
- 感知产品 —— 可以包含业务逻辑、布局假设和特定组合
用法
通过 CLI 安装,然后从你的项目中导入:
# 初始化配置(仅首次需要)
npx @cloudflare/kumo init
# 列出可用的区块
npx @cloudflare/kumo blocks
# 将区块安装到你的项目
npx @cloudflare/kumo add PageHeader
安装完成后,从本地路径导入:
// 路径取决于你的 kumo.json blocksDir 设置
// 默认:src/components/kumo/
import { PageHeader } from "./components/kumo/page-header/page-header";
区块代码现在归你所有。定制它、扩展它、把它拆散——你的产品需要什么就做什么。
一个实际例子
来看一个 ProductCard。它是针对特定用例的特定组件排布:
// 这是一个"区块"或"配方" —— 针对特定模式的
// 设计系统组件的特定组合
<Surface className="rounded-lg p-4">
<img src={imgSrc} alt={imgAlt} className="rounded-md" />
<div className="mt-3">
<Text size="lg" weight="semibold">
{title}
</Text>
<Text className="text-kumo-subtle">{description}</Text>
<StarRating rating={rating} />
</div>
<div className="mt-4">
<Button variant="primary">Add to cart</Button>
</div>
</Surface>
所有这些组件 (Surface、Text、Button) 都来自 Kumo。但这种特定排布呢?那是你拥有并定制的模式。
决策框架
问”这是组件还是区块?“实际上是在问所有权与复用:
选择组件,当……
- 它与内容无关 (适用于任何数据)
- 它与上下文无关 (适用于任何布局)
- 多个产品需要完全相同的东西
- 无障碍和一致性最重要
- 你希望获得自动更新与维护
选择区块,当……
- 你需要在属性之外做定制
- 该模式是特定于产品的
- 它包含业务逻辑或布局假设
- 你希望完全掌控实现
- 你更倾向于复制粘贴而非包依赖
默认优先想”组件”。 即使在构建某个特定内容时,也问问自己:“我能用现有组件构建它吗?“答案通常是可以。组件可以组合成区块,而区块也随时可以再次拆解。
层级之间的流动
事物可以在这些类别之间流动。一个最初在应用中一次性使用的模式,可能因为被广泛使用而值得抽取为区块。一个被证明普遍有用的区块,也可能晋升为正式组件。
关键原则: 事物应当向_下_流入设计系统,而不是让过于具体的模式充斥其中、日后还需逐一清理。在把某样东西晋升为共享组件之前,先等待复用证明其价值。
这就是区块作为中间地带存在的原因。它们是值得分享的模式,但不必承担维护版本化 API 的承诺。你获得起点;演进归你所有。
总结
| 组件 | 区块 | |
|---|---|---|
| 交付方式 | npm 包导入 | CLI 复制到你的项目 |
| 所有权 | Kumo 维护 | 你拥有并定制 |
| 更新 | 升级版本号自动更新 | 手动 (重新安装或合并) |
| 定制 | 仅限属性与 className | 完整源码访问 |
| 示例 | Button、Input、Dialog、Badge | PageHeader、ResourceList |