拼豆图库包含动漫、游戏、偶像、场景和设计师五组内容。每组都有主色、浅背景、图片蒙层、卡片底色、角标、符号和副标题。如果每个视觉字段都写一组 if (category === ...),页面很快会出现七八条平行判断链。
本文把这些规则收口成类型化配置,让组件只消费视觉结果,不再负责解释分类;同时保留默认项,保证旧数据或未知分类不会让页面失去样式。

一、平行判断链会悄悄产生视觉漂移
当 categoryTint()、categorySoftBg()、categoryMark() 和 categorySubtitle() 分散存在时,新增分类必须修改多处函数。漏改任何一处都不会报错,却可能出现"背景是新分类、角标还是默认值"的混搭。
这类问题的本质是同一个业务实体被拆成多条无关联分支。正确方向不是继续封装更多函数,而是把一个分类的完整视觉规则放在同一个对象中。
二、把分类键收窄为有限集合
先阻止任意字符串进入视觉系统:
ts
export type CategoryKey =
'anime' | 'game' | 'idol' | 'scene' | 'designer' | 'default'
export interface CategoryVisualConfig {
tint: ResourceColor
softBg: ResourceColor
imageVeil: ResourceColor
cardTint: ResourceColor
accent: ResourceColor
mark: string
corner: string
subtitle: string
}
字段清单就是视觉契约。评审新增分类时,可以直接确认颜色、文案和装饰是否齐全。
三、同一分类的规则必须相邻
把五组配置放入一个映射,下面展示其中三组及默认项:
ts
export const CATEGORY_VISUALS: Record<CategoryKey, CategoryVisualConfig> = {
anime: {
tint: '#FFE2F0', softBg: '#FFF0F7', imageVeil: '#35FFF0F8',
cardTint: '#FFF1F5', accent: ThemeTokens.brandPink,
mark: '漫', corner: '✦', subtitle: '魔法少女与学院角色'
},
game: {
tint: '#DDEEFF', softBg: '#EEF6FF', imageVeil: '#35EAF6FF',
cardTint: '#EEF8FF', accent: ThemeTokens.sky,
mark: '游', corner: '◇', subtitle: '勇者、法师与像素冒险'
},
scene: {
tint: '#DFF5DD', softBg: '#ECF9EA', imageVeil: '#35ECFFE9',
cardTint: '#F0FAEA', accent: ThemeTokens.mintDark,
mark: '景', corner: '☾', subtitle: '樱花街角与梦幻小屋'
},
idol: {
tint: '#FFF0B8', softBg: '#FFF8DF', imageVeil: '#35FFF2D9',
cardTint: '#FFF7E5', accent: '#D78E00',
mark: '星', corner: '♡', subtitle: '舞台应援 Q 版爱豆'
},
designer: {
tint: '#F1DDFF', softBg: '#F8EEFF', imageVeil: '#35F6EAFF',
cardTint: '#F4EDFF', accent: '#A368D8',
mark: '潮', corner: '✧', subtitle: '潮玩盲盒原创娃娃'
},
default: {
tint: '#F4F0F3', softBg: '#F8F5F7', imageVeil: '#35FFFFFF',
cardTint: '#FFFCFD', accent: ThemeTokens.ink,
mark: '图', corner: '☆', subtitle: '精选编号图纸'
}
}
每组配置独立成块,修改场景色时不会误碰游戏副标题。
四、在单一入口处理未知分类
数据层中的 Pattern.category 可能仍是 string,尤其需要兼容旧记录时。不要在每个组件强制断言,统一通过解析函数进入有限集合:
ts
export function toCategoryKey(value: string): CategoryKey {
if (value === 'anime' || value === 'game' || value === 'idol' ||
value === 'scene' || value === 'designer') {
return value
}
return 'default'
}
export function visualOf(category: string): CategoryVisualConfig {
return CATEGORY_VISUALS[toCategoryKey(category)]
}
默认项是兼容边界,不是让错误分类长期沉默的理由。数据校验仍应记录未知值,界面则使用安全样式继续展示。

五、组件一次读取,连续消费
组件不再重复调用七个分类函数,只读取一个配置对象:
ts
@Builder
private CategoryCard(item: CategoryItem) {
Column() {
Text(visualOf(item.key).corner)
.fontColor(visualOf(item.key).accent)
Text(visualOf(item.key).mark)
.fontColor(visualOf(item.key).accent)
Text(visualOf(item.key).subtitle)
.fontColor(ThemeTokens.inkSoft)
}
.backgroundColor(visualOf(item.key).cardTint)
}
更进一步,可以在数据准备阶段把视觉配置附加到视图数据,避免一次构建中重复解析:
ts
export interface CategoryViewData {
item: CategoryItem
visual: CategoryVisualConfig
}
六、业务数据和视觉数据不要互相复制
Pattern 只保存 category,不应把 tint、corner 等字段重复写入每张图纸。否则调整主题后要迁移所有旧记录。
推荐关系是:
text
Pattern.category
↓
toCategoryKey()
↓
CATEGORY_VISUALS
↓
CategoryCard / PatternCard / Cover
分类键是稳定业务数据,具体颜色和文案是可演进的展示规则,两者通过读取关系连接。
七、主题色优先引用 ThemeTokens
配置表并不意味着重新堆积十六进制颜色。品牌色、正文色、背景色等跨页面语义仍应引用 ThemeTokens;只有分类专属色保留在分类配置中。
ts
designer: {
tint: '#F1DDFF',
softBg: '#F8EEFF',
imageVeil: '#35F6EAFF',
cardTint: '#F4EDFF',
accent: '#A368D8',
mark: '潮',
corner: '✧',
subtitle: '潮玩盲盒原创娃娃'
}
若分类色未来也需要深浅模式,可把 accent 替换为资源引用,配置结构不需要变化。
八、透明色要明确通道顺序
图片蒙层使用八位颜色,例如 #35FFF0F8。在当前 ArkUI 写法里应明确团队约定的通道顺序,并用一张小色块页面验证透明度,避免有人按另一种顺序改成完全不同的颜色。
可以把蒙层透明度统一为同一档位,只改变 RGB 部分。这样五组卡片保持相近的图片可读性,不会有某一组蒙层过重遮住封面。
验证时选择同一张明暗对比明显的封面,分别套用五组蒙层,在浅色与深色系统外观下观察标题、角标和主体轮廓。若某组需要特殊透明度,也应把差异写进配置,而不是在组件里临时叠加第二层颜色。
九、配置完整性可以自动断言
配置表适合做关系校验:文字不可为空、角标应是短字符、默认项必须存在。
ts
export function validateCategoryVisuals(): string[] {
const issues: string[] = []
const keys: CategoryKey[] = [
'anime', 'game', 'idol', 'scene', 'designer', 'default'
]
keys.forEach((key: CategoryKey) => {
const visual = CATEGORY_VISUALS[key]
if (visual.mark.length === 0) {
issues.push(`${key} 缺少分类符号`)
}
if (visual.subtitle.trim().length === 0) {
issues.push(`${key} 缺少副标题`)
}
if (visual.corner.length > 2) {
issues.push(`${key} 的角标过长`)
}
})
return issues
}
这类断言无法判断颜色好不好看,却能防止新增分类时漏掉必要字段。
十、一次改造不要同时重做视觉
从判断链迁移到配置表时,应先保持现有颜色和文案完全不变。建议按以下顺序实施:
- 录入当前所有返回值;
- 给旧函数与新配置输入同一分类,比较结果;
- 组件改读
visualOf(); - 删除已经没有引用的旧函数;
- 最后再单独调整某个分类视觉。
结构改造和视觉改版分开,出现差异时更容易判断来源。

十一、落地检查清单
- 分类键是有限类型;
- 一个分类的全部视觉字段放在同一对象;
- 未知分类统一回退到
default; - 组件不再编写分类判断链;
Pattern不重复保存视觉字段;- 跨页面语义色继续使用
ThemeTokens; - 五组现有视觉在迁移前后保持一致。
迁移验收可以截取五组分类卡片、图纸卡片和分类封面各一屏,与改造前逐项比较。只有配置读取路径发生变化,颜色、符号、副标题和回退行为都不应改变,这样后续视觉调整才有干净的基线。
总结
配置表的价值不只是减少代码行数,而是让"一组分类视觉"重新成为一个完整对象。五组规则集中后,新增字段、调整主题和排查样式差异都有唯一入口;ArkUI 组件只负责展示,不再承担分类解释逻辑。对于分类丰富的 Harmony os 图库,这种单一映射能显著降低视觉漂移。
标签:Harmony os、ArkTS、ArkUI、配置化、主题设计