HarmonyOS应用开发实战:猫猫大作战-模运算条件样式、三元表达式样式、enum 映射色、等级色函数四种套路


前言
上一篇我们用双层 ForEach 把 5×8 棋盘网格渲出来,但每格背景色写的是 (row+col)%2 === 0 ? '#F0F4F8' : '#E6EDF3'——这个「模运算条件样式」一眼看似简单,实则是 ArkUI 响应式样式的核心套路:三元表达式根据数据动态返回样式值。这种套路在棋盘色、状态色、等级色、性别色等场景反复出现。
本篇以「猫猫大作战」棋盘隔行变色为锚点,把模运算条件样式、三元表达式样式、enum 映射色、等级色函数四种套路讲透。读完本篇你将能独立写出:棋盘格变色、等级色映射、状态色切换、条件圆角四种动态样式。
提示:本系列不讲 ArkTS 基础语法与环境搭建,假设你已跟完第 1–13 篇。
一、场景拆解:棋盘色三元表达式
回顾 GameView 第 1 层棋盘背景:
// 来源:entry/src/main/ets/pages/Index.ets GameView() 棋盘格
Stack() {
Text('').fontSize(20)
}
.width(`${100 / COLS}%`).height(`${100 / ROWS}%`)
.backgroundColor((row + col) % 2 === 0 ? '#F0F4F8' : '#E6EDF3')
核心:.backgroundColor(...) 的参数是一个三元表达式,根据 (row+col)%2 的奇偶性动态返回浅色或深色。
二、三元表达式在样式中的合法位
ArkUI 的属性方法(.fontSize/.backgroundColor/.borderRadius 等)接受任意返回合法类型的表达式——包括三元、函数调用、常量。
2.1 三元表达式样式
.backgroundColor((row + col) % 2 === 0 ? '#F0F4F8' : '#E6EDF3')
.fontSize(isTitle ? 20 : 14)
.borderRadius(isCard ? 12 : 0)
.fontColor(isActive ? '#2ECC71' : '#95A5A6')
语法:条件 ? 真值 : 假值。条件为 true 返回真值,否则返回假值。
2.2 嵌套三元(多条件)
.backgroundColor(
row === 0 ? '#FFC107' : // 第 0 行黄(预警行)
row === 1 ? '#E74C3C' : // 第 1 行红(危险行)
row === 2 ? '#FFFFFF' : // 第 2 行白(安全行)
'#F8F9FA' // 其余浅灰
)
嵌套三元用于多条件分支——但超过 3 层可读性崩,应改用函数(第 4 节讲)。
2.3 三元 vs if/else
// ✅ 三元:在属性参数里合法
.backgroundColor((row + col) % 2 === 0 ? '#F0F4F8' : '#E6EDF3')
// ❌ if/else:不能写在属性参数里
.backgroundColor(if (cond) { '#F0F4F8' } else { '#E6EDF3' }) // 语法错!
关键:ArkUI 属性参数里只能用三元,不能用 if/else——if 是语句不是表达式,没有返回值。
三、模运算的四种棋盘色套路
3.1 (row+col)%2 棋盘格(本项目)
(row + col) % 2 === 0 ? '#F0F4F8' : '#E6EDF3'
色分布:相邻格永远异色,经典棋盘。
| 行\列 | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 0 | 浅 | 深 | 浅 | 深 |
| 1 | 深 | 浅 | 深 | 浅 |
| 2 | 浅 | 深 | 浅 | 深 |
3.2 row%2 行间变色
row % 2 === 0 ? '#F8F9FA' : '#FFFFFF'
色分布:相邻行异色,同行同色。适合列表项变色。
3.3 col%2 列间变色
col % 2 === 0 ? '#F8F9FA' : '#FFFFFF'
色分布:相邻列异色,同列同色。适合横向卡片变色。
3.4 (row*2+col)%3 三色循环
[(row * 2 + col) % 3, '#FFC107', '#FF9800', '#E74C3C'] // 伪代码,实际用函数
色分布:三色循环,视觉更丰富但易花,慎用。
四、enum 等级色映射实战
打开 GameTypes.ets,猫咪有 6 级:
export enum CatLevel {
LEVEL_1, // 0
LEVEL_2, // 1
LEVEL_3, // 2
LEVEL_4, // 3
LEVEL_5, // 4
LEVEL_6 // 5
}
每级对应一个颜色,渲染时要根据 cat.level 返回对应色。嵌套三元写 6 层就崩,应改用函数 + switch:
getCatColor(level: CatLevel): string {
switch (level) {
case CatLevel.LEVEL_1: return '#FFC107' // 黄
case CatLevel.LEVEL_2: return '#FF9800' // 橙
case CatLevel.LEVEL_3: return '#E74C3C' // 红
case CatLevel.LEVEL_4: return '#9B59B6' // 紫
case CatLevel.LEVEL_5: return '#2ECC71' // 绿
case CatLevel.LEVEL_6: return '#3498DB' // 蓝
default: return '#FFC107'
}
}
// 使用:
Text(this.getCatEmoji(cat.level))
.fontSize(30)
.backgroundColor(this.getCatColor(cat.level))
4.1 Record 映射表替代 switch
const CAT_COLOR: Record<number, string> = {
[CatLevel.LEVEL_1]: '#FFC107',
[CatLevel.LEVEL_2]: '#FF9800',
[CatLevel.LEVEL_3]: '#E74C3C',
[CatLevel.LEVEL_4]: '#9B59B6',
[CatLevel.LEVEL_5]: '#2ECC71',
[CatLevel.LEVEL_6]: '#3498DB'
}
getCatColor(level: CatLevel): string {
return CAT_COLOR[level] ?? '#FFC107' // ?? 防空
}
Record 映射表优势:
- O(1) 查询:比 switch O(n) 快。
- 数据驱动:颜色改一处即可,不动函数。
- 易扩展:加级只需加一行。
提示:ArkTS 严格模式禁
any,Record<K, V>是真正的字典映射类型,替代 JS 的{}动态对象。本系列第 115 篇会专讲Record。
4.2 资源引用替代硬编码色
const CAT_COLOR: Record<number, Resource> = {
[CatLevel.LEVEL_1]: $r('app.color.cat_level_1'),
[CatLevel.LEVEL_2]: $r('app.color.cat_level_2'),
// ...
}
用 $r('app.color.xxx') 资源引用替代 '#FFC107' 硬编码——暗色模式切换自动适配。本系列第 28 篇会专讲暗色模式。
五、状态色切换实战
GameState 也有色映射:
getGameStateColor(state: GameState): string {
switch (state) {
case GameState.IDLE: return '#95A5A6' // 灰:待机
case GameState.PLAYING: return '#2ECC71' // 绿:游玩
case GameState.PAUSED: return '#FFC107' // 黄:暂停
case GameState.GAME_OVER: return '#E74C3C' // 红:结束
default: return '#95A5A6'
}
}
// 使用:状态指示器
Circle({ width: 12, height: 12 }).fillColor(this.getGameStateColor(this.gameState))
状态色语义:
| 状态 | 色 | 语义 |
|---|---|---|
| IDLE | 灰 | 静默 |
| PLAYING | 绿 | 活跃 |
| PAUSED | 黄 | 等待 |
| GAME_OVER | 红 | 警告 |
六、条件圆角实战
圆角也能用三元动态控:
// 棋盘格:方角
Stack() { /* ... */ }
.borderRadius(0)
// 棋子:圆角
Text(this.getCatEmoji(cat.level))
.borderRadius(cat.level >= 5 ? 50 : 12) // 高级猫咪更圆,5+ 级用 50(近圆)
// 卡片:中圆角
Column() { /* ... */ }
.borderRadius(isModal ? 24 : 12) // 模态卡片更圆
条件圆角套路:根据数据动态控圆角,让视觉语义随状态变化。
七、完整代码:四种动态样式对比
7.1 棋盘色(三元表达式)
Stack() {
Text('').fontSize(20)
}
.width(`${100 / COLS}%`).height(`${100 / ROWS}%`)
.backgroundColor((row + col) % 2 === 0 ? '#F0F4F8' : '#E6EDF3')
7.2 等级色(函数 + switch)
getCatColor(level: CatLevel): string {
switch (level) {
case CatLevel.LEVEL_1: return '#FFC107'
case CatLevel.LEVEL_2: return '#FF9800'
case CatLevel.LEVEL_3: return '#E74C3C'
case CatLevel.LEVEL_4: return '#9B59B6'
case CatLevel.LEVEL_5: return '#2ECC71'
case CatLevel.LEVEL_6: return '#3498DB'
default: return '#FFC107'
}
}
Text(this.getCatEmoji(cat.level))
.fontSize(30)
.backgroundColor(this.getCatColor(cat.level))
.borderRadius(8)
7.3 状态色(Record 映射表)
const STATE_COLOR: Record<number, string> = {
[GameState.IDLE]: '#95A5A6',
[GameState.PLAYING]: '#2ECC71',
[GameState.PAUSED]: '#FFC107',
[GameState.GAME_OVER]: '#E74C3C'
}
getGameStateColor(state: GameState): string {
return STATE_COLOR[state] ?? '#95A5A6'
}
Circle({ width: 12, height: 12 }).fillColor(this.getGameStateColor(this.gameState))
7.4 条件圆角(三元嵌套)
Text(this.getCatEmoji(cat.level))
.fontSize(30)
.borderRadius(cat.level >= 5 ? 50 : 12) // 5+ 级近圆,其余小圆角
八、调试技巧:动态样式怎么调
console.info打色值:Builder 里加console.info('color', this.getCatColor(cat.level)),追实际渲染色。- 临时固定色验证:把三元临时改成固定
'#F00'(红),看所有格是否都红——验证表达式是否被调用。 - 密钥冲突排查:格子少几个?查
(row+col)%2是否依赖了重复的 row/col 值。 - 真机看色:预览器渲染接近真机,但某些色相可能因屏密度差异,以真机为准。
九、性能与最佳实践
- 三元表达式比函数调用快:简单 2 分支用三元,避免函数调用开销。
- 复杂分支用函数 + switch/Record:超 3 分支别嵌套三元,可读性崩。
- Record 映射表 O(1) 查询:比 switch O(n) 快,大数据量必用。
- 资源引用替硬编码色:
$r('app.color.xxx')支持暗色模式,硬编码不支持。
总结
本篇我们从棋盘隔行变色切入,掌握三元表达式条件样式、模运算四种棋盘色套路、enum 等级色映射(switch/Record)、状态色切换、条件圆角五大要点,并给出了四种动态样式的完整代码。核心要点:属性参数用三元非 if/else,简单 2 分支用三元,复杂分支用函数 + Record 映射,资源引用替硬编码。
下一篇我们将继续游戏页,拆解猫咪渲染的 Emoji Text 与圆形背景。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- 「猫猫大作战」项目源码:本仓库
entry/src/main/ets/pages/Index.ets - ForEach 循环渲染官方指南
- 文本显示 (Text/Span) 官方指南
- Shape 容器官方指南
- 开源鸿蒙跨平台社区
- HarmonyOS 开发者官方文档首页
- 系列索引:本仓库
articles/INDEX.md
更多推荐

所有评论(0)