发布时间:2026/7/14 19:01:21
新特性:设计系统(Design System)构建 —— 建立团队的 Token 变量库 文章目录前言一、为什么需要 Token 变量库1.1 硬编码的四大问题1.2 Token 解决什么1.3 与现有 DSTokens.ets 的关系二、HarmonyOS 资源体系速览2.1 目录结构2.2 引用语法2.3 单位约定三、命名规范语义化而非描述色值3.1 推荐格式3.2 好的命名 vs 坏的命名3.3 完整 Token 清单Demo四、定义颜色 Token4.1 base/element/color.json4.2 dark/element/color.json4.3 对比一览五、定义间距与圆角 Token5.1 float.json 完整定义5.2 4vp 网格原则5.3 引用示例六、在组件中消费 Token6.1 迁移前 vs 迁移后6.2 Demo 组件画廊6.3 色板数据驱动七、暗色模式零代码适配7.1 原理7.2 开发注意事项7.3 容器色的暗色处理八、团队落地工作流8.1 设计 → 开发协作8.2 渐进式迁移策略8.3 与 Styles / Extend 结合8.4 Code Review 检查项九、常见误区9.1 「Token 就是常量类」9.2 「暗色模式在组件里判断」9.3 「Token 名用色值描述」9.4 「间距随意定」9.5 「只定义亮色」十、Token 规模参考十一、总结前言打开一个三个月前写的页面你可能会看到.fontColor(#6B7280).padding(12).borderRadius(10).backgroundColor(#2563EB)当时觉得「就几个魔法数字记得住」。三个月后品牌色从#2563EB换成#0A59F7设计师要求暗色模式适配间距从 12 统一调到 16——你需要在几十个文件里全文搜索替换漏一处就是视觉不一致。这就是没有设计系统的代价。Design System设计系统的核心产物之一是Token 变量库——把颜色、间距、圆角、字号等视觉属性抽象成语义化变量集中定义在resources目录组件通过$r(app.color.ds_text_primary)引用而非硬编码。HarmonyOS 的资源体系basedark双目录天然支持主题切换。本文结合项目 Demo从 Token 理念、资源定义、引用方式、暗色适配到组件落地做一次完整实战解析。读完后你应该能回答什么是语义化 Token和直接写色值有什么区别颜色、间距、圆角分别放在哪个 JSON 文件$r()如何在 ArkUI 组件中使用如何实现「改一处 resources全 App 换肤」一、为什么需要 Token 变量库1.1 硬编码的四大问题问题后果散落各处同一个#2563EB出现 80 次改品牌色要改 80 处语义缺失#6B7280是标题色还是提示色新人无法判断无法换肤暗色模式需在每个组件写if (isDark)协作断裂设计师给 Figma Token开发手写 hex两边对不上1.2 Token 解决什么Token 是设计决策的命名快照设计师说「主文本用 text-primary」 开发写 .fontColor($r(app.color.ds_text_primary)) 资源文件ds_text_primary #111827亮色/ #F9FAFB暗色改色只改color.json。加暗色只加dark/color.json同名条目。组件代码一行不动。1.3 与现有 DSTokens.ets 的关系项目中designsystem/tokens/DSTokens.ets用 TypeScript 常量定义 TokenexportclassDSColor{staticreadonlybrandPrimary#0A59F7}这适合纯逻辑层或跨 module 编译期引用但不支持系统级主题切换——暗色模式来了要手动判断。本文推荐的resources Token则由框架在运行时按主题自动选取是 HarmonyOS 官方推荐的视觉变量管理方式。两者可并存resources 管颜色/尺寸ETS 类管枚举和组件变体。二、HarmonyOS 资源体系速览2.1 目录结构entry/src/main/resources/ ├── base/ ← 默认亮色资源 │ └── element/ │ ├── color.json ← 颜色 Token │ ├── float.json ← 间距/圆角/字号 Token │ └── string.json └── dark/ ← 暗色覆写 └── element/ └── color.json ← 同名 Token暗色值系统根据当前主题自动选择base或dark目录下的同名资源。组件始终引用$r(app.color.ds_text_primary)无需关心当前是亮是暗。2.2 引用语法// 颜色.fontColor($r(app.color.ds_text_primary)).backgroundColor($r(app.color.ds_bg_surface))// 间距 / 圆角 / 字号.padding($r(app.float.ds_space_lg)).borderRadius($r(app.float.ds_radius_md)).fontSize($r(app.float.ds_font_body1))格式$r(app.type.name)其中type对应 JSON 文件名color、float、string。2.3 单位约定文件常用单位用途color.json#RRGGBB颜色值float.jsonvp间距、圆角随屏幕密度缩放float.jsonfp字号随系统字体缩放Demo 间距用vp字号用fp符合 HarmonyOS 适配规范。三、命名规范语义化而非描述色值3.1 推荐格式ds_category_role部分含义示例ds_设计系统前缀避免与业务资源冲突—category类别text、bg、space、radiusrole语义角色primary、secondary、md、lg3.2 好的命名 vs 坏的命名✅ 语义化❌ 描述性ds_text_primaryds_gray_900ds_brand_primaryds_blue_500ds_bg_surfaceds_whiteds_space_mdds_twelve_vp语义化命名的好处品牌色从蓝变绿Token 名ds_brand_primary不用改只改值。ds_blue_500则名实不符制造混乱。3.3 完整 Token 清单Demo颜色17 个类别Token品牌/语义ds_brand_primary,ds_brand_primary_container,ds_success,ds_success_container,ds_warning,ds_warning_container,ds_danger,ds_danger_container文本ds_text_primary,ds_text_secondary,ds_text_tertiary,ds_text_inverse表面ds_bg_page,ds_bg_surface,ds_bg_elevated,ds_border_default,ds_border_strong,ds_divider间距6 级4vp 网格Token值ds_space_xs4vpds_space_sm8vpds_space_md12vpds_space_lg16vpds_space_xl24vpds_space_xxl32vp圆角5 级Token值典型场景ds_radius_sm6vp小标签、徽标ds_radius_md10vp按钮、输入框ds_radius_lg16vp卡片、面板ds_radius_xl24vp底部弹窗ds_radius_full999vp胶囊、圆形字阶6 级Token值ds_font_caption10fpds_font_body212fpds_font_body114fpds_font_subtitle16fpds_font_title20fpds_font_headline24fp四、定义颜色 Token4.1 base/element/color.json{color:[{name:ds_brand_primary,value:#2563EB},{name:ds_text_primary,value:#111827},{name:ds_bg_page,value:#F9FAFB},{name:ds_bg_surface,value:#FFFFFF}]}容器色*_container是 Material Design 3 风格主色的低饱和背景用于标签、选中态、提示区块。Demo 中ds_brand_primary_container #EFF6FF与ds_brand_primary #2563EB配对使用。4.2 dark/element/color.json暗色目录中定义同名 Token赋予不同值{color:[{name:ds_text_primary,value:#F9FAFB},{name:ds_bg_page,value:#111827},{name:ds_bg_surface,value:#1F2937},{name:ds_brand_primary,value:#60A5FA}]}注意暗色模式下品牌色通常提高亮度#2563EB→#60A5FA而非简单反转以保证对比度和可读性。4.3 对比一览Token亮色 (base)暗色 (dark)ds_text_primary#111827#F9FAFBds_text_secondary#6B7280#9CA3AFds_bg_page#F9FAFB#111827ds_bg_surface#FFFFFF#1F2937ds_brand_primary#2563EB#60A5FADemo 在「色彩 Token」场景底部有暗色模式提示切换系统暗色后所有引用$r(app.color.ds_*)的组件自动更新无需任何代码修改。五、定义间距与圆角 Token5.1 float.json 完整定义{float:[{name:ds_space_xs,value:4vp},{name:ds_space_sm,value:8vp},{name:ds_space_md,value:12vp},{name:ds_space_lg,value:16vp},{name:ds_space_xl,value:24vp},{name:ds_space_xxl,value:32vp},{name:ds_radius_sm,value:6vp},{name:ds_radius_md,value:10vp},{name:ds_radius_lg,value:16vp},{name:ds_radius_xl,value:24vp},{name:ds_radius_full,value:999vp}]}5.2 4vp 网格原则间距刻度以4vp 为基数4、8、12、16、24、32。这保证所有间距是 4 的倍数视觉节奏统一设计师在 Figma 中用 8px 网格开发用 8vp心算对齐避免padding(13)这种「拍脑袋」数值Demo「间距 Token」场景用色条直观展示各级长度并附有 padding 实战卡片。5.3 引用示例// 统一内边距.padding($r(app.float.ds_space_lg))// 方向性内边距.padding({left:$r(app.float.ds_space_md),right:$r(app.float.ds_space_md),top:$r(app.float.ds_space_sm),bottom:$r(app.float.ds_space_sm)})// 圆角.borderRadius($r(app.float.ds_radius_lg))// Column 间距Column({space:12})// 注意space 参数目前只接受 number暂不能用 Resource最后一个注意点Column({ space })等布局参数的space在某些 API 版本只接受number不支持$r()。这类场景可暂时保留数字或在Builder封装层统一处理。颜色、padding、borderRadius、fontSize 等属性已广泛支持 Resource 类型。六、在组件中消费 Token6.1 迁移前 vs 迁移后// ❌ 硬编码Text(标题).fontSize(22).fontColor(#111827)Column().padding(16).backgroundColor(#FFFFFF).borderRadius(12)// ✅ Token 驱动Text(标题).fontSize($r(app.float.ds_font_headline)).fontColor($r(app.color.ds_text_primary))Column().padding($r(app.float.ds_space_lg)).backgroundColor($r(app.color.ds_bg_surface)).borderRadius($r(app.float.ds_radius_lg))6.2 Demo 组件画廊「组件应用」场景展示四类组件全部零硬编码按钮Text(主按钮).fontColor($r(app.color.ds_text_inverse)).backgroundColor($r(app.color.ds_brand_primary)).borderRadius($r(app.float.ds_radius_md)).padding({left:$r(app.float.ds_space_md),right:$r(app.float.ds_space_md),top:$r(app.float.ds_space_sm),bottom:$r(app.float.ds_space_sm)})卡片Column({space:8}).padding($r(app.float.ds_space_lg)).backgroundColor($r(app.color.ds_bg_surface)).borderRadius($r(app.float.ds_radius_lg)).border({width:1,color:$r(app.color.ds_border_default)})标签品牌/成功/警告/危险四色Text(成功).fontColor($r(app.color.ds_success)).backgroundColor($r(app.color.ds_success_container)).borderRadius($r(app.float.ds_radius_full))语义色 容器色配对是设计系统的标准做法文字用高饱和色背景用低饱和同色系。6.3 色板数据驱动Demo 将 Token 组织为可遍历数组便于文档化展示interfaceColorSwatch{id:stringtoken:stringlabel:stringcolor:ResourceColor}constBRAND_SWATCHES:ColorSwatch[][{id:c1,token:ds_brand_primary,label:主色,color:$r(app.color.ds_brand_primary)}]$r()返回值可直接存入常量数组ForEach 渲染色板——这也是团队内部 Token 文档页的常见实现。七、暗色模式零代码适配7.1 原理组件引用 $r(app.color.ds_bg_page) │ ▼ 系统判断当前主题 ╱ ╲ base/color.json dark/color.json #F9FAFB #111827组件层不出现任何isDarkMode判断。资源框架在运行时解析正确的值。7.2 开发注意事项所有颜色必须走 Token— 一个#FFFFFF漏网就会暗色下刺眼暗色值不是简单反转— 品牌色提亮、边框色减淡需设计稿校准对比度—ds_text_primary与ds_bg_surface在两端都需满足 WCAG AA对比度 ≥ 4.5:1测试方法— 系统设置切换暗色或在 DevEco 预览器选择 dark 主题7.3 容器色的暗色处理亮色ds_success_container #ECFDF5浅绿底暗色ds_success_container #064E3B深绿底容器色在暗色模式下反而加深避免大面积浅色刺眼同时保持语义色相。八、团队落地工作流8.1 设计 → 开发协作Figma Design Tokens │ ▼ 导出/对照 resources/color.json float.json │ ▼ 引用 $r(app.color.ds_*) 全 App 消费 │ ▼ 变更 只改 JSON → 全 App 生效建议在设计稿中直接使用与代码一致的 Token 名ds_text_primary减少翻译损耗。8.2 渐进式迁移策略不必一次性重构全 App。推荐顺序阶段范围做法Phase 1新页面强制使用 Token禁止硬编码Phase 2核心组件Button、Card、Input 封装 TokenPhase 3存量页面按模块逐步替换#hex→$r()Phase 4审查CI 脚本扫描硬编码色值8.3 与 Styles / Extend 结合对于重复样式组合可封装Extend(Text)functiondsBody1(){.fontSize($r(app.float.ds_font_body1)).fontColor($r(app.color.ds_text_primary))}Extend(Column)functiondsCard(){.padding($r(app.float.ds_space_lg)).backgroundColor($r(app.color.ds_bg_surface)).borderRadius($r(app.float.ds_radius_lg)).border({width:1,color:$r(app.color.ds_border_default)})}// 使用Text(正文).dsBody1()Column().dsCard()Token 定义「值」Extend 定义「组合」—— 两层分工避免每个组件重复写五六个属性。8.4 Code Review 检查项新增颜色是否定义为 Token组件是否使用$r()而非 hex暗色color.json是否有对应覆写间距是否为 4vp 网格倍数命名是否符合ds_category_role规范九、常见误区9.1 「Token 就是常量类」DSColor.brandPrimary #2563EB在 TypeScript 里编译期固定无法响应系统主题切换。resources Token 才是运行时主题感知的正解。常量类可作为补充不应替代 resources。9.2 「暗色模式在组件里判断」// 不推荐.fontColor(this.isDark?#F9FAFB:#111827)// 推荐.fontColor($r(app.color.ds_text_primary))前者每处都要写判断后者集中管理。9.3 「Token 名用色值描述」ds_blue_500在品牌换色后名不副实。用语义名ds_brand_primary值可以随便换。9.4 「间距随意定」padding(15)、margin(13)破坏网格节奏。Stick to the scalexs/sm/md/lg/xl/xxl。9.5 「只定义亮色」暗色适配不是可选项。从第一天就在dark/color.json维护同名 Token成本远低于事后补。十、Token 规模参考Demo 当前规模类型数量文件颜色17color.json × 2间距6float.json圆角5float.json字阶6float.json合计34—一个中等复杂度 App颜色 Token 通常在 20–40 个间距/圆角/字号各 5–8 个。不宜贪多——每个 Token 都应有明确使用场景否则团队记不住。扩展时优先加语义色如ds_info、ds_link而非加第 17 个灰色变体。十一、总结设计系统 Token 变量库的本质是把视觉决策从组件代码中抽离到 resources定义一次 → 处处引用 → 改一处全局生效HarmonyOS 落地三件套文件放什么引用方式base/element/color.json语义化颜色$r(app.color.ds_*)dark/element/color.json暗色覆写同名自动切换base/element/float.json间距/圆角/字号$r(app.float.ds_*)关键原则语义命名—ds_text_primary不是ds_gray_9004vp 网格— 间距刻度可预期零硬编码— 组件不出现#hex魔法数字双目录主题— base dark 同名 Token渐进迁移— 新代码强制 Token存量逐步替换本文 Demo 在四个场景中完整展示了色板、间距刻度、圆角阶梯和组件画廊。建议你在真机上运行后到系统设置切换暗色模式——观察ds_bg_page从浅灰变为深蓝灰而组件代码一行未改。这就是 Token 变量库的价值。设计系统不是设计师的文档摆设而是开发团队的视觉基础设施。从第一个ds_brand_primary开始你的 App 就拥有了统一的语言。相关文件Demo 页面entry/src/main/ets/pages/Index.ets亮色 Tokenentry/src/main/resources/base/element/color.json、float.json暗色 Tokenentry/src/main/resources/dark/element/color.json编译命令node/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw.js assembleHap-pproductdefault-pbuildModedebug --no-daemon

相关新闻

2026/7/14 19:01:21

数字文化体验馆技术解析与运营实践

1. 数字文化体验馆的兴起背景2023年第一季度全国新建数字文化体验馆数量同比增长47%,这个数字背后反映的是地方政府对文化数字化战略的积极响应。我在参与多个省级文化馆数字化改造项目时发现,决策者普遍将这类场馆视为"新基建"在文化领域的重…

2026/7/14 19:01:21

鸿蒙 ArkTS 实战:Poetry Cards 从状态建模到交互闭环完整解析

鸿蒙 ArkTS 实战:Poetry Cards 从状态建模到交互闭环完整解析 前言 Poetry Cards 是一个面向 学习成长工具 的鸿蒙 ArkTS 小应用。管理诗词卡片、收藏状态和背诵模式。 本文围绕项目中的 entry/src/main/ets/pages/Index.ets 展开,拆解它的 数据模型、…

2026/7/14 19:01:21

FineReport(帆软报表)V11.05安装使用教程

软件下载 官网下载地址 官方下载中心 - FineReport免费下载 点击下图所示进行下载 点击保留 软件安装 右键以管理员身份运行 点击是 稍等下 点击下一步 选择我接受协议,点击下一步 选择安装路径,点击下一步 这里设置jvm内存,建议设置2G或以…

2026/7/14 19:51:23

HydroViewer-在线水动力模拟可视化解决方案

水文水动力模拟是研究水体运动与水文过程的重要方法,可以帮助我们深入理解水资源管理、洪涝灾害预警、河流生态恢复等问题。然而,传统的水文水动力模拟结果的可视化分析存在一些限制,如需要安装特定软件、数据处理困难以及与其他模型的集成问…

2026/7/14 19:51:23

TB67H480FNG+STM32F103RC步进电机控制方案解析

1. 为什么选择TB67H480FNGSTM32F103RC组合在工业自动化和小型运动控制领域,电机驱动方案的选择往往决定了整个项目的性能上限。TB67H480FNG作为东芝新一代双极步进电机驱动器,与STM32F103RC这款经典Cortex-M3微控制器的组合,正在成为越来越多…

2026/7/14 19:51:23

【信息科学与工程学】【物理/化学和工程技术】第一百三十二篇 损伤学 系列二01 ——网络中的损伤学02

进一步拓展到6G太赫兹通信、量子传感网络、生物启发网络、数字孪生网络、语义通信、空天地一体化、算力网络、确定性网络、AI原生网络、水下通信等前沿领域,同时深化传统网络损伤分析。 编号 类型 领域 问题 问题的详细数学分析【需考虑几何/结构/质量分布/时间/介质分布/…

2026/7/14 12:47:32

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南

3步解锁音乐自由:ncmdumpGUI终极NCM文件解密转换指南 【免费下载链接】ncmdumpGUI C#版本网易云音乐ncm文件格式转换,Windows图形界面版本 项目地址: https://gitcode.com/gh_mirrors/nc/ncmdumpGUI 你是否曾在网易云音乐下载了心爱的歌曲&#…

2026/7/14 19:23:19

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境

CANoe 19 SP3 配置 GB/T 27930-2023 A类系统:3步搭建BMS仿真测试环境随着新能源汽车行业的快速发展,充电通信协议的标准化和测试验证变得尤为重要。GB/T 27930-2023作为中国智能充电协议的最新版本,对充电机与电动汽车之间的通信提出了更严格…

2026/7/14 18:30:06

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡

3步搞定RTL8852BE驱动:从零开始配置Wi-Fi 6网卡 【免费下载链接】rtl8852be Realtek Linux WLAN Driver for RTL8852BE 项目地址: https://gitcode.com/gh_mirrors/rt/rtl8852be 还在为Linux系统无法识别RTL8852BE Wi-Fi 6网卡而烦恼吗?&#x1f…

2026/7/14 0:04:21

5分钟掌握足球PBR材质制作:Photoshop与Unity高效工作流

1. 项目概述:为什么是足球PBR材质?在游戏开发,尤其是体育竞技类游戏的制作中,一个看起来“对味”的足球,往往比我们想象中更重要。它不仅是赛场上的核心道具,更是玩家视觉焦点和沉浸感的重要来源。一个塑料…

2026/7/14 0:04:21

ChatGPT联网搜索失败,92%开发者误判为网络问题——真实根因竟是LLM推理会话上下文污染导致Search Agent进程静默退出(含strace复现脚本)

更多请点击: https://intelliparadigm.com 第一章:ChatGPT 联网搜索失败 当 ChatGPT 的联网搜索功能无法正常工作时,用户常遇到“搜索不可用”“未连接到互联网”或空白响应等现象。该问题并非模型本身缺陷,而是由权限配置、网络…

2026/7/14 12:47:31

3个高效策略:快速掌握Axure中文界面配置

3个高效策略:快速掌握Axure中文界面配置 【免费下载链接】axure-cn Chinese language file for Axure RP. Axure RP 简体中文语言包。支持 Axure 11、10、9。不定期更新。 项目地址: https://gitcode.com/gh_mirrors/ax/axure-cn 还在为Axure RP的英文界面感…