【寻迹校园 HarmonyOS NEXT 实战 06】共享权威词表:让发布表单与首页筛选使用同一套分类
【寻迹校园 HarmonyOS NEXT 实战 06】共享权威词表:让发布表单与首页筛选使用同一套分类
这是“寻迹校园 HarmonyOS NEXT 实战”系列第 6 篇。本文结合
ReportTaxonomy.ets,说明 HarmonyOS NEXT 应用如何用稳定内部值、展示标签和筛选关键词建立共享权威词表,避免发布、筛选和旧数据回显互相打架。

上图为本文原创生成的词表治理概念图,不是项目截图。它强调一个核心事实:页面可以有不同文案,但分类和区域的业务含义只能有一个权威来源。
一、同一个地点为什么会出现三种写法
校园失物招领看起来只是填写分类和地点,实际很容易产生数据漂移。例如同一个位置可能同时出现:
- 发布页保存“第一教学楼附近”;
- 首页筛选按钮显示“第一教学楼”;
- 匹配规则使用“第一教学楼”做包含判断;
- 旧版本数据里还保存过“教学一号楼”。
如果每个页面各维护一份字符串数组,短期能运行,后续会出现三个问题:发布记录无法被筛选命中、旧记录无法正确回显、修改文案时必须同时寻找多个页面。
解决方案不是在每次比较前堆更多 if,而是建立共享权威词表,让“展示给用户的名称”“真正写入数据的稳定值”和“用于模糊筛选的关键词”各司其职。
二、稳定值、展示标签和筛选关键词不能混为一谈
项目为区域定义了一个简单模型:
export class ReportAreaOption {
label: string = '';
value: string = '';
filterKeyword: string = '';
constructor(label: string, value: string, filterKeyword: string) {
this.label = label;
this.value = value;
this.filterKeyword = filterKeyword;
}
}
三个字段分别解决不同问题:
| 字段 | 责任 | 示例 |
|---|---|---|
label |
页面按钮与筛选项展示 | 第一教学楼 |
value |
发布记录真正保存的值 | 第一教学楼附近 |
filterKeyword |
首页模糊筛选和旧文本兼容 | 第一教学楼 |
如果把三个概念压成一个字符串,文案调整就会变成数据迁移。把它们拆开后,页面可以显示更简洁的名称,业务数据仍保留足够语义,筛选也不必要求完全相等。
三、9 类物品和 7 个区域只定义一次
“寻迹校园”当前单校演示词表包含 9 个物品分类:箱包、证卡、数码、钥匙、衣物、雨具、水杯、书籍和其他。
区域词表包含 7 个入口:第一教学楼、图书馆、体育馆、食堂、保卫处、宿舍区和其他区域。真实代码集中在 common-core:
export const REPORT_CATEGORY_OPTIONS: string[] = [
'箱包', '证卡', '数码', '钥匙', '衣物',
'雨具', '水杯', '书籍', '其他'
];
export const REPORT_AREA_OPTIONS: ReportAreaOption[] = [
new ReportAreaOption('第一教学楼', '第一教学楼附近', '第一教学楼'),
new ReportAreaOption('图书馆', '图书馆服务台', '图书馆'),
new ReportAreaOption('体育馆', '体育馆入口', '体育馆'),
new ReportAreaOption('食堂', '食堂二楼', '食堂'),
new ReportAreaOption('保卫处', '保卫处失物招领点', '保卫处'),
new ReportAreaOption('宿舍区', '宿舍区服务站', '宿舍区'),
new ReportAreaOption('其他区域', '其他校内区域', '其他')
];
词表放在 common-core 而不是某个页面中,是因为发布页、首页筛选、匹配规则和测试都需要引用它。它属于跨模块业务契约,不属于任何单一 UI。
四、发布页保存 value,首页筛选使用 filterKeyword
发布页为用户展示 label,选中后写入 value:
private areaOption(option: ReportAreaOption) {
Button(option.label)
.onClick(() => {
this.area = option.value;
this.validation = new PublishValidation();
})
}
首页筛选则复制同一份 REPORT_AREA_OPTIONS,读取 filterKeyword 构造查询。这样,“图书馆服务台”能够被“图书馆”筛选命中,而页面不需要知道发布页保存了什么长文案。
这也是稳定键和值的重要区别:用户看到的是可调整文案,业务判断依赖的是稳定数据含义。

上图展示从发布选择、稳定值保存到首页筛选命中的映射链。每次修改词表时,应该沿这条链检查展示、存储、筛选和历史记录,而不是只看当前页面按钮。
五、旧数据不能因为词表升级而消失
共享词表上线前,设备里可能已经存在自定义值或旧版本区域。编辑这些记录时,如果下拉项只渲染新词表,旧值会无法选中,用户甚至会误以为数据丢失。
项目的兼容方式是:先复制权威选项,再把当前记录中不存在于新词表的值追加为临时保留项。
private areaOptions(): ReportAreaOption[] {
const options: ReportAreaOption[] = [];
REPORT_AREA_OPTIONS.forEach((option: ReportAreaOption) => options.push(option));
if (this.area.trim().length > 0 &&
!options.some((option: ReportAreaOption) => option.value === this.area)) {
options.push(new ReportAreaOption(`保留:${this.area}`, this.area, this.area));
}
return options;
}
分类也采用相同策略:当前值不在 9 类权威分类中时,把它追加到页面可选项。这样可以做到“新数据使用新词表,旧数据仍可读取和编辑”,避免一次 UI 调整破坏历史数据。
六、为什么不要在页面里复制数组
页面内复制词表通常会留下这些隐患:
- 发布页新增“雨具”,首页筛选忘记增加;
- 一个页面写“数码产品”,另一个页面写“数码”;
- 测试使用第三份硬编码数据,全部通过但真实页面不一致;
- 旧值兼容只在编辑页处理,详情页仍显示空白;
- 多模块项目出现循环依赖,被迫从页面反向导入常量。
正确的依赖方向应该是:entry 页面依赖 common-core 词表,Service 和纯规则同样依赖 common-core,但 common-core 永远不依赖页面。
七、词表治理还需要哪些验证
仅仅把数组挪到公共文件还不够。一次词表变更至少要验证:
- 发布页的分类和区域按钮数量正确;
- 选中区域后保存的是
value,不是label; - 首页筛选使用
filterKeyword,能够命中更长的保存值; - 编辑旧记录时,未知分类与区域仍能回显;
- 匹配规则不会把“其他区域”当成高置信相同地点;
- 空值、长文本和旧版本脏数据有兜底;
- 单元测试直接导入权威词表,而不是复制期望数组。
这些检查比“页面上看起来一致”更可靠,因为它们覆盖了写入、读取、筛选和升级四个方向。
八、跨校版本不能继续把校园字典写死
当前 9 类物品和 7 个区域适合单校比赛演示,但不能直接包装成通用校园平台。不同学校的校区、楼栋、服务台和命名方式差异很大。
跨校版本至少需要引入:
campusId和校区维度;- 可版本化的校园区域字典;
- 服务端或配置包下发;
- 旧版本字典迁移策略;
- 离线缓存和失效时间;
- 管理端审核,避免任意地点进入公共词表。
因此本文描述的是当前单机应用的权威词表设计,不宣称已经具备跨校配置中心。
九、用户视角下的直接收益
词表治理看似是代码整洁问题,实际会直接影响用户:发布后能否被搜索到、编辑旧记录时是否丢值、筛选按钮是否能稳定命中、匹配理由是否使用用户理解的区域名称。
共享权威词表把这些体验从“多个页面碰巧一致”变成可测试契约,也让后续增加分类、调整文案和升级数据时有明确影响范围。
十、一次词表变更需要做影响分析
共享词表集中之后,修改入口变少了,但一次改动的影响范围反而更应该写清楚。以“图书馆”更名为“中心图书馆”为例,不能只修改按钮文字,还要判断这是展示调整、搜索关键词扩充,还是存储值迁移。三种改动对应的风险完全不同。
| 变更类型 | 可以直接修改的内容 | 必须额外检查的内容 |
|---|---|---|
| 仅优化展示文案 | label |
小屏截断、无障碍朗读、设计稿文案 |
| 扩充搜索命中范围 | filterKeyword 或别名集合 |
误命中、性能、历史记录检索 |
| 修改持久化含义 | value |
旧数据迁移、回滚、统计口径、跨版本兼容 |
| 删除分类或区域 | 新数据入口 | 旧记录回显、编辑保存、详情页兜底 |
实际开发中,可以把每次词表变更写成一个小型影响单:变更原因、旧值、新值、读取方、写入方、迁移策略、回滚方式和验收场景。这样代码审查者看到的不只是“数组改了一行”,而是完整的数据契约变化。
十一、迁移、回滚与脏数据处理
如果只是调整 label,通常不需要迁移数据库;如果要替换 value,则必须先确认设备中是否已经存在旧值。稳妥流程是先让新版本同时识别新旧值,再把新发布记录写成新值,最后在有充分验证后逐步迁移历史数据。直接删除旧值会让用户已经发布的记录变成无法筛选的孤岛。
回滚同样不能只恢复代码。假设新版本已经写入“中心图书馆服务台”,旧版本却只认识“图书馆服务台”,应用降级后仍可能出现未知值。因此回滚方案要么保证旧版本可以通过“保留:当前值”路径展示,要么在数据迁移时保留可逆映射。对于比赛演示项目,即使没有复杂数据库迁移脚本,也应把这个边界写进测试和交付说明。
脏数据处理还应区分空字符串、前后空格、未知分类、未知区域和过长自定义文本。页面负责给出友好提示,Service 负责最终校验,Repository 负责读取失败和默认值兜底。不要在 UI 中悄悄把未知值改成“其他”,因为这会改变用户原始记录的含义。
十二、团队协作和可追踪验收
多人协作时,权威词表的改动应该由一个明确模块负责,页面需求不能各自复制常量“先做出来”。代码审查至少要回答:是否新增了稳定值、是否影响旧记录、筛选是否仍能命中、是否需要修改测试、是否改变了单校演示边界。只有展示文案变化时,也要确认没有误改 value。
交付验收可以使用用户语言,而不是只写“常量已抽取”:
- 用户在发布页选择“图书馆”后,保存并返回首页能够被“图书馆”筛选命中;
- 旧版本保存的自定义地点进入编辑页后仍能看到原值,不会被自动清空;
- 新增分类在发布、详情、筛选和匹配说明中采用一致名称;
- 删除入口后,历史记录仍可读取,且用户知道它属于保留数据;
- 应用重启后再次查询,结果与保存前一致,不依赖页面内存状态。
这些验收语句把技术实现与真实体验连接起来,也便于后续定位问题究竟发生在展示、写入、读取还是筛选阶段。
十三、本文小结
在 HarmonyOS NEXT 多模块项目中,分类和区域不是普通页面常量,而是写入、筛选、匹配和历史兼容共同依赖的业务契约。
label / value / filterKeyword 的拆分让展示、存储和搜索各自稳定;common-core 统一持有词表,页面只消费;旧值通过临时保留项继续回显。下一篇将继续解决另一个跨页面问题:不引入全局状态库,如何用 dataRevision 让首页、消息和“我的发布”重新读取权威数据。
系列导航:第 6 篇 / 共 50 篇。上一篇:《Page → Service → Repository》;下一篇:《用 dataRevision 实现跨页面刷新信号》。
更多推荐


所有评论(0)