一个做组件库的团队最怕的不是写不出组件而是写出一堆没人用的组件。这半年我们一直在琢磨一件事怎么让一套 UI 组件库从“能跑”变成“好用”进而真正支撑起企业级 App 的复杂业务。盯着 HarmonyOS 6 的发布节奏我们把过去积累的设计规范、业务组件、性能优化经验全部沉淀下来最终产出了这套内部代号为 HarmonyUI 的企业级组件库。这篇文章算是一份开发日志记录我们这半年的关键决策、踩坑记录和最终落地效果希望能给正在做类似事情的团队一些参考。1. 项目背景与目标拆解为什么非做不可1.1 立项的导火索业务迭代被 UI 拖了后腿这事的起因其实不复杂。我们团队维护着一个用户量不小的跨端应用过去半年里业务方提了不下二十次“页面样式不统一”“新页面开发周期太长”的意见。排查下来根子出在组件上各业务线各自为政有人用开源库改样式有人自己写一套还有人直接把设计稿切成图片往代码里塞。等到应用要适配 HarmonyOS 6 的时候问题彻底爆发了——语法不兼容、布局行为不一致、状态管理方式对不上光兼容这些零零碎碎的组件就占掉了两个迭代周期。所以立这个项目的目标很直白做一套统一、规范、高性能、可扩展的组件库把多端复用和业务迭代速度提上来。不是简单地把 Web 端那套组件翻译成 HarmonyOS 的语法而是针对鸿蒙原生特性重新设计。当时团队内部还讨论过要不要直接改开源库来适配试了一个星期就放弃了原因后面细说。1.2 目标用户的隐性需求开发者体验比组件本身更关键我观察到一个容易被忽略的点组件库的使用者不只是业务开发还有设计师、测试、甚至项目经理。业务开发关心的是“接入够不够快、参数够不够灵活”设计师关心的是“组件能不能还原设计规范”测试关心的是“交互状态全不全、有没有暗黑模式适配”项目经理关心的是“组件文档清不清楚、排期可不可控”。所以我们把组件库的目标拆成了四层第一层是功能完整性必须覆盖常用业务场景第二层是视觉一致性所有组件遵守同一套设计令牌第三层是性能与稳定性滚动列表、弹窗这类高频组件不能出现卡顿和闪烁第四层是开发者体验文档要能搜、示例要能跑、参数要被类型约束住。这四层缺一不可只做第一层那叫组件集合全做到才叫组件库。1.3 技术选型上的第一个岔路口改开源还是自研这块必须展开讲因为太容易让人纠结了。市面上不是没有开源的鸿蒙 UI 库但拉下来用了一圈发现问题很集中一是组件之间的风格协调性差A 库的按钮配 B 库的弹窗视觉上明显不对二是对企业级场景支持不够像权限弹窗、渠道检测、灰度配置这类能力几乎没有现成的三是升级维护不可控开源库的迭代方向大概率跟着社区的热点走跟我们的业务节奏对不上。最后我们决定自研但这个“自研”不是从零开始画轮子而是站在系统能力和设计规范之上做定制。底层用 HarmonyOS 6 的官方组件做地基上层把设计令牌、业务组件、工具方法全部收拢到一套体系里。这样既保证了和系统的兼容性又能把企业级场景的差异化需求做深。2. 整体架构与设计思路把组件库当成产品做2.1 分层设计从底层能力到业务组件的三层结构HarmonyUI 的整体架构分了三层从下往上依次是基础能力层、通用组件层、业务组件层。这个分层思路跟盖楼差不多底层的稳定性决定上层能盖多高。基础能力层包含设计令牌Design Token、主题系统、工具函数、基础动画曲线。这一层不做任何带业务语义的组件只负责提供颜色、字体、间距、圆角、阴影、动效时长这些原子化的属性。所有组件只从这一层取值不写死任何颜色值。这样做最大的好处是换肤和暗黑模式变得极其简单只要切换一套令牌整个组件库的视觉风格就全变了不需要每个组件都改一遍。通用组件层放的是大家熟悉的那些基础控件按钮、输入框、选择器、弹窗、Toast、列表、导航栏等等。这一层的要求是每个组件能独立使用、能自由组合同时支持主题注入。业务层是我们投入精力最多的地方像用户头像墙、订单卡片、富文本公告、扫码弹窗、协议勾选组件都属于这一层。它们直接面向业务场景内部会组合多个通用组件并且与数据请求逻辑打通。三层之间依赖关系是单向的不允许上层反向依赖或跨层调用这是一个硬约束Review 代码时发现跨层依赖会直接打回。2.2 核心设计原则约束优先自由在后做组件库这半年我深刻体会到一条原则给使用者太多自由反而是灾难的开始。举个例子如果按钮组件的颜色属性完全开放业务方这个页面传一个金色那个页面传一个紫色视觉规范很快就失控。所以 HarmonyUI 在设计上主动做了约束组件只暴露“语义化”的属性比如色调类型分成主色、成功、警告、危险四类而不是把十六进制色值的字符串暴露出去。业务方要么用预设风格要么走扩展接口去注册新风格不能直接在组件上写死色值。这样做的代价是组件库的 API 设计难度变大好处是一致性目标从源头得到了保障。我们在设计阶段讨论 API 时有一条很实用的判断标准如果一个属性超过三成的业务场景都用不上就不应该出现在 Props 里如果某个需求反复出现说明应该把它内化成组件能力而不是让业务方自己搭。这套“约束优先自由在后”的原则后来跟业务方对齐时获得了很好的反馈因为他们也知道自由是要付出维护成本的。2.3 为什么专注 HarmonyOS 6 而不是直接做多端统一坦白说我们最开始讨论过要不要做一套跨端方案一套代码同时输出到鸿蒙和现有平台。但调研后发现HarmonyOS 6 的布局、动效、状态管理模型都有自己的特点强行抹平差异的结果往往是两端体验都打折扣还多出一层维护复杂度。最后决定先聚焦鸿蒙端把原生能力吃透后续再做多端但保持设计令牌和组件语义的统一这样未来跨端时切换成本也不会太高。事实也证明这个选择是对的。我们做滚动列表性能优化时直接用了 HarmonyOS 系统提供的懒加载机制和布局缓存策略效果非常明显。如果当初用跨端方案这层系统级的优化很难触达。聚焦单一平台让我们有机会把性能体验做到一个更高的标准。3. 核心组件实现细节从设计到代码的落地过程3.1 按钮与输入框组件细节藏在交互状态里按钮是所有组件库的门面但它的细节远不止“一个圆角矩形 文字”这么简单。我们在做按钮组件时重点处理了三类状态加载状态、禁用状态和点击反馈。加载状态要求按钮内的文字和图标整体切换成加载指示器且布局不能发生抖动禁用状态要有明确的视觉降级但不能影响布局占位点击反馈则利用系统提供的点击缩放能力配合一个标准的按压动效曲线来实现。这三个状态在代码层面都要做独立的布局分支和属性透传不能图省事用一个透明度全覆盖。输入框组件比按钮更麻烦一点因为它的交互触点更多。我们需要处理聚焦边框颜色切换、占位提示动画、清除按钮的显隐时机、密码框的明文切换、错误状态下的描述信息展示。最难的其实是“清除按钮的显隐时机”——聚焦时且内容非空才显示失焦后即便有内容也要隐藏避免遮挡用户查看已输入的文字。这个逻辑看似简单但处理不好就会出现闪烁问题后来我们通过在状态变化处统一走一个内部状态机来解决而不是在多个回调里分散修改状态。3.2 弹窗与 Toast切断跟业务生命周期的耦合是关键弹窗类组件做不好最容易出现的问题有两个弹窗关闭后回调里的状态没有清理导致内存泄漏弹窗弹出时机不确定跟业务页面的生命周期产生冲突。HarmonyUI 里的弹窗组件做成了一套独立的层级系统由组件库内部的弹窗管理容器来调度而不是直接挂到页面节点上。这样弹窗跟在哪个页面之上无关自己管理自己的显示层级和关闭动画业务方只需要关心弹窗的内容和确认回调。Toast 的细节也不少主要在多实例处理和连续弹出策略上。快速点击按钮连续触发多条 Toast我们的策略是后一条覆盖前一条而不是排队依次显示。因为用户感知中最新的提示通常最重要。我们把 Toast 的显示时长设计成系统级变量语义分为短、中、长三档业务方只能在预设档位里选不允许自定义毫秒数避免了那种超长 Toast 赖在屏幕上不走的问题。3.3 复杂列表组件性能问题被用户感知前就要解决列表是移动端使用频率最高的组件也是性能问题的重灾区。HarmonyUI 的列表组件在架构上直接采用了平台的懒加载数据源并且额外做了一层节流和复用优化。具体来说当数据源发生变化时我们只通知列表刷新变化的行而不是整表刷新滚动过程中通过预加载因子提前渲染下一个屏幕的内容同时配合布局缓存让回收的列表项对象可以被直接复用减少创建和销毁的开销。这项优化前后对比数据很直观单屏 50 条数据的列表优化前滚动掉帧率约 12%优化后降到了 2% 以内内存峰值降低了约 30%。我们内部达成了一个性能红线凡是面向列表的组件加载和滚动时不允许出现可感知的掉帧。这条红线在后续每个组件迭代中都会被反复验证。3.4 主题与暗黑模式一套令牌机制搞定全局换肤HarmonyOS 6 的系统级深色模式适配是我们组件库的一个基础能力所有组件默认支持不需要业务方额外开发。实现上我们建立了一套完整的设计令牌体系颜色全部用语义化名称来定义背景基础色、背景强调色、文字主色、文字辅助色、分割线色、遮罩层色等等。日常模式下赋值一套色值暗黑模式下赋值另一套色值组件内不写死任何一个颜色。这套体系延伸出来的能力还包括品牌换肤。有次一个合作方想在应用里使用他们的品牌色我们把整套主色令牌换成品牌色后重新编译全局配色就全变了只用了半天时间。之前改业务代码里的颜色没个一星期根本下不来。这就是设计令牌带来的杠杆效应投入在底层收益体现在所有组件上。4. 测试与质量保障组件库的日常保养手册4.1 单测加场景测试组件库不能只靠联调发现问题组件库跟业务代码不一样业务代码出了问题影响范围往往是一条业务逻辑组件库出了问题影响的是所有接入方。所以测试这一环必须前置不能等着业务方联调时再发现问题。HarmonyUI 的要求是每个组件除了核心渲染逻辑的单测覆盖外还要有一套组件验收测试和场景测试。验收测试主要验证组件的 API 行为是否符合设计文档包括参数边界情况、事件回调触发次数、状态切换后的视图表现。场景测试则是模拟真实使用环境比如弹窗连续开关是否异常、输入框快速输入时是否会丢字、深色模式和浅色模式切换时组件是否有闪烁。测试数据上也有一些心得。组件的测试用例不能只写正常路径错误路径至少要占一半。很多崩溃和异常都发生在边界输入上比如传空字符串、传超长文本、传非法枚举值。我们用的测试框架支持在多种分辨率下跑同一套用例确保不同屏幕尺寸上组件表现稳定这一点对企业级应用非常重要。4.2 视觉回归测试让设计师不再靠肉眼一个个挑组件库迭代过程中最容易被忽略但又最容易伤感情的就是视觉回归问题。某个版本改了边框粗细按钮看起来就是跟设计稿不一样了如果靠人去逐一对比效率极低还容易漏。我们搭了一套视觉回归测试流程为每个组件生成一份标准截图库每次提交代码后自动渲染新截图跟基准截图做像素级对比差异超过阈值就标注出来给开发者确认。是预期变化就更新基准图非预期变化则定位到具体改动点回滚修复。这条流程上线后设计师那边反馈很明显特别是在做圆角、阴影、间距这类细微样式调整的时候他们不用再一张张切图去比对测试用例截图直接就能说明问题。有了这套机制我们甚至有底气在大版本里统一调整所有组件的圆角半径而不担心某个犄角旮旯的组件被漏掉。4.3 兼容性测试从 API 版本和设备型号两个维度铺开HarmonyOS 6 虽然是一个大版本但市面上还有大量存量设备停留在旧版本上。组件库需要明确支持的最低版本并在这个区间上做好兼容。我们的口径是核心组件兼容至 API 9但部分依赖新特性的组件只在高版本启用增强能力通过特性检测来渐进增强而不是引入一堆代码库去兼容一切。这样既保证了存量用户的基本体验又让新设备上能有更好的表现。真机测试同样不能省。模拟器跑不出真机的性能特征像滚动掉帧、内存占用、冷启动时间必须在真机上测。我们准备了一个覆盖高中低端性能的设备池每一轮版本发布前至少跑一轮全量真机回归。有次发现低端机上列表快速滑动会白屏排查后发现是布局缓存对象池在极端情况下没有正确回收这个问题在模拟器上根本复现不了。5. 发布与接入落地组件库真正被用起来的过程5.1 组件库的发布节奏小步快跑的同时保持版本稳定组件库发布过晚业务方等不起发布太频繁业务方升级成本又太高。我们最终定的节奏是每两周一个迭代版本每两个月一个稳定大版本。迭代版本里可以包含新组件和优化项但标记为测试状态大版本才是推荐全业务接入的稳定版本。同时引入语义化版本号破坏性变更必须是大版本号的变化并且随版本发布一份变更记录和升级导览告诉接入方这次要改哪里、怎么改。发布流程上我们做了双轨制组件库内部走完整的 CI 流程包括单测、视觉回归、性能测试、文档构建业务方侧只消费稳定产包和类型描述文件。这样既保证质量又不过度打扰业务方的构建流程。产包走专门的制品库不经过公共仓库避免依赖污染。5.2 从 0 到 1 的接入支持文档写得好接入成本才真的低文档是一套组件库的隐形价值但它的重要性往往要到接入阶段才会凸显。我们给文档定了几条硬指标每个组件必须有可运行的示例代码、参数说明表、默认值标注、常见问题区、变更记录。示例代码统一放在一个 Playground 环境里业务方可以直接改参数看效果能直接复制的代码才叫好文档。我们内部还有个“接入新人测试”机制每次版本发布前会找一个没参与组件库开发的同事拿着文档从零接入一个 Demo 页面记录从上手到跑通的时间。这个时间超过半小时就说明文档还有优化空间会返工补充。半年下来新人的平均接入时间从最初的半天降到了两小时内文档和类型提示的作用功不可没。5.3 组件库内部的灰度机制先让一部分业务先用起来组件库要上线不能所有业务线一把梭直接切。我们制定了一套灰度策略先找一两个业务形态合适、版本节奏跟我们匹配的业务线试点用真实需求倒逼组件质量试点稳定后扩展到中等体量业务最后才推广到全业务线。每一阶都有反馈收集和问题处理时限出现阻断性问题可以随时回滚到上一版本。这不只是规避风险的手段也是建立信任的过程。业务方对组件库的信任是靠一两个高质量组件案例建立起来的。我们在一个核心业务页面上全部换用 HarmonyUI 组件后页面包体积缩小了 20%开发周期缩短了约三分之一。这个数据迅速传播开后续业务方的接入意愿明显增强进入了一个正向循环。6. 踩坑记录与问题排查实录6.1 状态管理引发的组件内部状态错乱问题组件库运行过程中最怕遇到的是“偶现问题”。某次收到反馈弹窗在连续快速打开关闭几次后内部状态会错乱关闭动画结束后内容区域有残留。排查发现问题出在组件的显隐状态变更和动画状态变更没有完全同步。关闭动画还在播放时组件状态就被强制重置导致内容层提前回收。这类问题在今天回头看解法不算复杂把所有显隐状态收拢到一个地方管理动画开始、播放中、结束分别对应不同的状态分支不能在动画过程中直接修改核心数据。重要的是排查过程的思路不要凭经验改代码先用录屏或者日志把每次状态变化打点输出找出哪一步开始跟预期不一致再定位是哪个模块的责任。6.2 组件库版本升级导致的颜色闪变问题另一个印象深刻的坑是深色模式切换时部分页面会出现轻微的闪白。刚开始以为是组件库的取色逻辑问题查了很久发现其实跟产包的加载顺序有关。某个页面的背景色在组件库的样式表生效之前先用了系统默认背景色深色模式下系统默认背景色偏白就闪了一下。最后我们的解法很朴素组件库在入口处统一注入一个初始背景色令牌并把这个令牌设置为与深色模式一致的预设值这样组件库样式加载前的瞬间页面也不会暴露错误底色。这个问题也提醒我们组件库的工作不只是封装组件还要考虑到组件挂载前整个页面的状态。6.3 性能优化的误判不能只看渲染时长有段时间我们的列表组件在优化后单次渲染时长已经降得很低但用户反馈滑动时还是有卡顿。后来分析才发现问题出在数据请求和渲染的衔接上列表数据源更新时机太密集导致渲染被频繁打断。真正的瓶颈不在于单帧渲染时长而在于帧之间的调度是否均匀。从那以后我们对任何性能优化的验证都从三个维度来看单次渲染耗时、帧间隔均衡度、内存占用稳定性。只看单项指标的优化是片面的特别是列表这种高频交互组件稳定性比峰值性能更重要。这也是组件库研发跟普通业务页面研发最大的不同之一业务页面跑通就行组件库必须跑得稳。7. 后续规划与个人总结7.1 未来优先做的三件事下一阶段有几件明确要推进的事。第一是继续扩充业务组件特别是把一些高频的行业专用组件标准化比如订单状态时间线、数据统计卡片、多选筛选面板这些都是业务提了很多次但仍需要重复开发的部分。第二是完善组件库的低代码配置能力让运营和后端同学可以在可视化界面里直接生成页面配置减少研发介入成本。第三是做更细的性能监控把组件库运行时的性能指标埋点上报持续追踪线上真实表现而不是依赖实验室测试。7.2 我的一些个人体会做了半年组件库最大的体会是“组件库没有做完的一天”。它更像是一个持续演进的产品要跟着业务跑、跟着系统跑、跟着设计潮流跑停下来的那一刻就意味着开始落后。团队内部的状态也很重要做组件库的成就感往往是滞后的——前面几个月全是投入看不到亮眼产出容易让人心浮气躁。我们这段时间的应对方式是设立固定展示节奏每两周把新增组件做成 Demo 在团队内公开演示让大家持续感受到进展和反馈。如果你们团队也在考虑做或者正在做类似的事情我最诚恳的建议有两条一是初期不要贪多先把最常用的二十个组件打磨到极致远好过一下铺开六七十个组件但每个都差一点二是花大力气把文档和示例代码做好那是组件库对外的一号脸面也是最容易被低估价值的环节。企业级 UI 组件库不是一个短期项目而是一份需要持续投入的组织资产前期把地基打牢后面每个业务方都会因此受益。