在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


目录

  1. 项目背景与动机
  2. 需求分析与功能规划
  3. 技术选型与环境搭建
  4. 数据建模:五笔字根数据结构设计
  5. JSON 模拟数据构建
  6. UI 架构与组件拆分
  7. 核心功能一:汉字搜索与实时检索
  8. 核心功能二:字根拆解展示与键盘分区渲染
  9. 核心功能三:五笔规则学习模块
  10. ArkTS API 24 关键技术挑战与解决方案
  11. 状态管理与数据流
  12. UI 主题与深色设计
  13. 常见问题与调试经验
  14. 项目总结与下一步规划

1. 项目背景与动机

1.1 为什么做这个工具

五笔字型(王码)作为中文输入的经典方案,以其「重码率低、输入速度快」著称。然而五笔的学习曲线较为陡峭——学习者需要记忆 130+ 个字根,并掌握「取大优先、能散不连、能连不交、兼顾直观」四大拆分规则。市场上现有的五笔学习工具存在以下痛点:

  • 桌面端工具老旧:大多为 Windows 单机软件,UI 落后,无法在手机上使用
  • 移动端工具简陋:简单展示编码,缺乏字根拆解的直观可视化
  • 缺少 HarmonyOS 原生应用:目前 AppGallery 上几乎没有基于 ArkTS 开发的五笔学习工具

本项目旨在填补这一空白,利用 HarmonyOS ArkTS API 24 构建一个轻量、高效、可交互的五笔偏旁拆解工具,帮助学习者通过「查字 → 看拆解 → 理解规则」的闭环快速掌握五笔。

1.2 目标用户

  • 五笔初学者(需要直观看到字根拆解过程)
  • 五笔进阶者(需要快速查询生僻字编码)
  • HarmonyOS 开发者(学习 ArkTS 实战技术)
  • 中文信息处理爱好者

2. 需求分析与功能规划

2.1 核心需求

需求 优先级 说明
汉字查编码 P0 输入汉字,返回五笔编码
字根拆解展示 P0 可视化展示每个字根的偏旁、键位、区号
难度分级 P1 基础/进阶/挑战三级,引导式学习
键盘分区展示 P1 显示五笔字母区的五个分区及对应键位
拆字规则说明 P1 内置四大规则和编码规则速查
快速查字 P2 常用字列表,点击即查
深色主题 P2 沉浸式学习体验

2.2 功能模块划分

┌──────────────┐
│  首页 (build) │
│  ├─ 导航标签  │
│  ├─ 查字模块   │ ← 核心
│  │  ├─ 搜索框  │
│  │  ├─ 结果卡片 │ ← 字根拆解可视化
│  │  └─ 常用字表 │ ← 快速查
│  ├─ 字根分区   │ ← 键盘分区学习
│  └─ 规则说明   │ ← 规则速查
└──────────────┘

2.3 UI 设计原则

  • 深色背景(#0A1628)减少长时间学习的视觉疲劳
  • 分区配色:横区红、竖区橙、撇区绿、捺区蓝、折区紫,每种颜色有自己的语义
  • 卡片化布局:每个信息单元独立成卡片,边界清晰
  • 响应式交互:输入即搜索,字根卡片带颜色边框

3. 技术选型与环境搭建

3.1 开发环境

项目 版本/工具
操作系统 Windows 11
开发工具 DevEco Studio NEXT
框架 HarmonyOS ArkTS
API 版本 API 24(HarmonyOS NEXT)
构建工具 hvigor(内置)
设备模拟 Phone 模拟器 / 真机

3.2 项目结构

MyApplication/
├── entry/
│   ├── src/main/
│   │   ├── ets/
│   │   │   └── pages/
│   │   │       └── Index.ets       ← 单文件 910 行,所有逻辑集中
│   │   ├── resources/
│   │   └── module.json5
│   └── build-profile.json5
└── docs/
    └── 五笔打字偏旁拆解工具开发实战.md  ← 本文

3.3 为什么选择单文件架构

虽然 ArkTS 支持模块化拆分,但本项目定位为极简工具类应用,单文件架构带来以下好处:

  1. 零配置导入:所有类型定义、数据、函数、组件在同一文件,无需 import/export
  2. 开发效率高:快速迭代,无需在多个文件间跳转
  3. 教学友好:学习 ArkTS 的开发者可以完整阅读全部代码
  4. 发布包体积小:无冗余模块加载

当然,如果项目扩展超过 1500 行,建议拆分为 model/data/components/pages/ 四个目录。


4. 数据建模:五笔字根数据结构设计

4.1 三层数据模型

我们设计了三个核心接口(Interface),构成了从「字根」→「汉字」→「键盘分区」的完整数据链路。

4.1.1 字根部件 RadicalPart
interface RadicalPart {
  radical: string   // 字根(偏旁部首),如 "日"、"月"、"木"
  key: string       // 对应键盘键位(大写字母),如 "J"、"E"、"S"
  name: string      // 字根名称,如 "日字旁"、"月字旁"
  zone: number      // 区号 1-5,对应五个分区
}

这个接口是最小数据单元。每个 RadicalPart 对象代表一个不可再拆分的字根本体。在设计时我们特别保留了 zone 字段——这为后续的字根颜色分区渲染提供了关键数据。

4.1.2 汉字条目 WubiEntry
interface WubiEntry {
  char: string          // 汉字
  code: string          // 五笔编码(大写字母)
  parts: RadicalPart[]  // 拆解的字根序列
  rule: string          // 拆解规则说明(自然语言)
  level: number         // 难度等级 1-3
}

这是应用的核心数据实体。与简单显示「汉字→编码」对照表的应用不同,我们通过 parts 数组记录了每个汉字的完整拆解过程,这是实现可视化字根展示的关键。

4.1.3 分区信息 ZoneInfo
interface ZoneInfo {
  zone: number    // 区号(1-5)
  name: string    // 分区名称,如 "横区"、"竖区"
  keys: string[]  // 该区包含的字母键,如 ['G','F','D','S','A']
  color: string   // 颜色代码,用于 UI 渲染
}

五笔键盘分为五个区:横区(GFDSA)、竖区(HJKLM)、撇区(TREWQ)、捺区(YUIOP)、折区(NBVCX)。每个区赋予独特的颜色,让用户在学习时建立「键位 ↔ 笔画 ↔ 颜色」的联想记忆。

4.2 为什么这样建模

这种三层建模的优势在于:

  1. 数据与展示分离RadicalPart.zone 决定了颜色,但颜色值定义在 ZoneInfo 中,修改配色不影响数据结构
  2. 支持动态渲染ForEach(entry.parts, ...) 可以直接渲染任意长度的字根序列,无需硬编码
  3. 可扩展性强:新增汉字只需添加一条 WubiEntry,无需修改任何 UI 代码
  4. 降级友好:如果某个汉字数据缺失,界面明确显示「未找到」,不会崩溃

5. JSON 模拟数据构建

5.1 数据规模与覆盖策略

由于无法在应用内打包完整的五笔字库(GB2312 含 6763 个汉字),我们精心挑选了 30+ 个代表性汉字,按照难度分为三级:

难度 特征 示例汉字 数量
⭐ 基础(lv1) 简单左右/上下结构 明、林、好、李、双、从、炎 ~12
⭐⭐ 进阶(lv2) 多重结构/品字结构 张、众、晶、品、森、鑫、赢 ~12
⭐⭐⭐ 挑战(lv3) 复杂结构/多字根 鑫(4 字根)、赢(5 字根) ~6+

5.2 数据类型覆盖策略

我们确保 mock 数据覆盖以下五笔编码模式:

类型 说明 示例 编码
二元字 两码 + 识别码 明 JEG 3 码
二元字无识别码 两码足够 从 WW 2 码
三元字 三码 + 识别码 晶 JJF 4 码
三元字无识别码 三码足够 众 WWW 3 码
四元字 字根 >= 4,取 1-2-3-末 赢 YNKY 4 码

5.3 数据示例

以「赢」字为例,这是五笔中最复杂的汉字之一:

{
  char: '赢', code: 'YNKY',
  parts: [
    { radical: '亡', key: 'Y', name: '亡字头', zone: 4 },
    { radical: '口', key: 'K', name: '口字旁', zone: 2 },
    { radical: '月', key: 'E', name: '月字旁', zone: 3 },
    { radical: '贝', key: 'M', name: '贝字底', zone: 2 },
    { radical: '凡', key: 'Y', name: '凡字底(末笔 Y)', zone: 4 }
  ],
  rule: '复杂字:亡(Y) + 口(K) + 月(E) + 贝(M) + 凡(Y),取 1-2-3-末码 YNKY(末笔取凡的末笔 Y)',
  level: 3
}

注意观察: 的键位都是 Y(捺区末笔),这种同键位不同字根的情况在 UI 渲染中通过 part.name 区分显示,体现了数据建模的精细度。


6. UI 架构与组件拆分

6.1 整体布局

整个应用被构建为一个 Column 容器,纵向排列三大区域:

┌─────────────────────────┐
│  Title (标题 + 副标题)     │  → Column + Text
├─────────────────────────┤
│  Tabs (导航标签)          │  → Row + @Builder TabBtn
├─────────────────────────┤
│  Scroll (内容区)          │  → Scroll
│  ├─ SearchSection (查字)  │  → @Builder
│  ├─ RadicalSection (字根) │  → @Builder
│  └─ RulesSection (规则)   │  → @Builder
└─────────────────────────┘

6.2 组件树(Component Tree)

Index (struct)
├── build()
│   ├── Title Text
│   ├── Tab Row
│   │   └── TabBtn × 3
│   ├── Scroll
│   │   └── (activeTab 条件渲染)
│   │       ├── SearchSection
│   │       │   ├── TextInput (搜索框)
│   │       │   ├── ResultCard (结果卡片)
│   │       │   │   ├── 大字 + 编码 Row
│   │       │   │   ├── 字根序列 Row
│   │       │   │   │   └── ForEach(entry.parts) → RadicalCard
│   │       │   │   ├── 编码拼合 Row
│   │       │   │   └── 规则说明 Row
│   │       │   ├── NotFoundCard (未找到提示)
│   │       │   └── 常用字网格
│   │       │       └── ForEach × 3 (LV1/LV2/LV3)
│   │       ├── RadicalSection
│   │       │   ├── ForEach(ZONES)
│   │       │   │   └── 分区卡片
│   │       │   │       └── ForEach(zone.keys) → 键位方块
│   │       │   └── 分区口诀
│   │       └── RulesSection
│   │           ├── RuleCard × 4 (四大规则)
│   │           └── 编码规则速查
│   │               └── CodeRuleRow × 6

6.3 @Builder 组件化设计

ArkTS 的 @Builder 是 API 24 中实现组件复用的核心装饰器。本应用共定义了 7 个 @Builder 函数:

@Builder 名称 用途 参数
TabBtn 导航标签按钮 label, section
SearchSection 查字模块容器(无参数)
ResultCard 字根拆解结果卡片 entry: WubiEntry
NotFoundCard 未找到提示卡片
RadicalSection 字根分区展示
RulesSection 规则说明页面
RuleCard 单条规则卡片 title, content, color
CodeRuleRow 编码规则行 label, desc
@Builder 的 ArkTS 规范

在 API 24 中,@Builder 有严格限制:

  1. 不能声明局部变量——所有值必须由参数传入或通过 this.xxx 访问
  2. 不能使用 return——但可以使用 return 作为 ForEach 的 keyGenerator 回调
  3. 内部可以是条件语句——if/else 允许,但不能是 switch/case
  4. 调用方式——无参时 this.BuilderName(),有参时 this.BuilderName(args)

⚠️ 踩坑记录:初版代码中我们在 ResultCard 内写了 const entry: WubiEntry = this.currentEntry as WubiEntry,结果 ArkTS 编译器报错。正确的做法是将 entry 作为参数传入 @Builder ResultCard(entry: WubiEntry)


7. 核心功能一:汉字搜索与实时检索

7.1 搜索机制设计

搜索功能的核心逻辑在 doSearch 方法中:

doSearch(char: string) {
  this.currentEntry = null
  this.notFound = false
  const entry = LOOKUP[char]
  if (entry !== undefined) {
    this.selectedChar = char
    this.currentEntry = entry
  } else {
    this.selectedChar = ''
    this.notFound = true
  }
}

整个过程分为三步:

  1. 重置状态:每次搜索前清空上次结果和错误标志
  2. O(1) 哈希查找:通过预构建的 LOOKUP 字典(Record<string, WubiEntry>)实现常数时间查询
  3. 状态分派:找到则渲染 ResultCard,否则渲染 NotFoundCard

7.2 输入即搜索(实时检索)

TextInputonChange 回调中实现了「输入即搜索」的交互模式:

TextInput({ placeholder: '输入汉字...', text: this.searchChar })
  .onChange((val: string) => {
    if (val.length > 0) {
      const lastChar = val.charAt(val.length - 1)  // 只取最后一个字符
      this.searchChar = lastChar
      this.doSearch(lastChar)
    } else {
      this.searchChar = ''
      this.currentEntry = null
      this.notFound = false
    }
  })

设计上做了两点取舍:

  • 只取末字符:五笔一次只查一个字,如果输入「汉字」只查「字」
  • 即时响应:不设搜索按钮,输入即查,提升交互流畅度

7.3 LOOKUP 字典的构建

为了支持 O(1) 查询,我们在模块加载时预构建了一个哈希字典:

const LOOKUP: Record<string, WubiEntry> = buildLookup()

function buildLookup(): Record<string, WubiEntry> {
  const map: Record<string, WubiEntry> = {}
  for (let i = 0; i < WUBI_DATA.length; i++) {
    const item = WUBI_DATA[i]
    if (map[item.char] === undefined) {
      map[item.char] = item
    }
  }
  return map
}

注意 if (map[item.char] === undefined) 的守卫——防止 char 字段在数据录入时重复导致后一条覆盖前一条。

7.4 常用字快速查

在搜索框下方,我们按难度分三行展示所有内置汉字:

基础 ⭐:明 林 好 李 双 从 炎 吕 昌
进阶 ⭐⭐:张 众 晶 品 森 鑫 矗
挑战 ⭐⭐⭐:赢 鑫(挑战级)...

每行使用 ForEach 遍历对应的 LV1/LV2/LV3 数组,点击任意汉字自动填充搜索框并触发查询。

ForEach(LV1, (item: WubiEntry) => {
  Text(item.char)
    .fontSize(16).fontColor('#FFFFFF')
    .padding({ left: 10, right: 10, top: 4, bottom: 4 })
    .backgroundColor('#111D33').borderRadius(8)
    .onClick(() => {
      this.searchChar = item.char
      this.doSearch(item.char)
    })
}, (item: WubiEntry) => item.char)   // ← 关键:ForEach 的第三个参数

每个字行用 Scroll(ScrollDirection.Horizontal) 包裹,确保手机小屏上可以横向滑动查看所有字。


8. 核心功能二:字根拆解展示与键盘分区渲染

8.1 结果卡片:字根拆解可视化

这是应用最核心的 UI 组件。ResultCard 接收一个 WubiEntry 参数,渲染四个区域:

区一:大字 + 编码概览
┌──────────────────────────────┐
│  明               五笔编码     │
│                    JEG        │
│                    ⭐ 基础     │
└──────────────────────────────┘

大字字号 48,编码字号 24 使用等宽字体,视觉层级清晰。

区二:字根序列
┌──────┐  ┌──────┐
│ 日   │  │ 月   │
│  J   │  │  E   │
│日字旁│  │月字旁│
│竖区  │  │撇区  │
└──────┘  └──────┘

每个字根以独立卡片呈现,包含四个信息层:

  1. 字根文字(28px 加粗白色)—— 视觉焦点
  2. 键位标识(14px 白色,带区色背景)—— 键位对应
  3. 字根名称(10px 浅色)—— 辅助识别
  4. 分区名称(9px 暗色)—— 分区归属

卡片颜色通过 zoneColor(part.zone) 函数计算:

function zoneColor(zone: number): string {
  for (let i = 0; i < ZONES.length; i++) {
    if (ZONES[i].zone === zone) {
      return ZONES[i].color
    }
  }
  return '#556677'  // 默认灰
}

每个字根卡片的边框也使用对应区色(透明度 0x44≈26%):

.border({ width: 1, color: zoneColor(part.zone) + '44' })

这种 「字根 → 颜色 → 键盘区」 的视觉映射,帮助用户建立五笔分区记忆。

区三:编码拼合
= J + E + G

将编码字母用 + 连接,让用户直观看到编码的构成逻辑。

区四:规则说明
📌 左右结构:日(J) + 月(E) + 末笔识别码(G)

以自然语言解释编码规则,辅助理解为什么是这个编码,而非死记硬背。

8.2 字根分区展示

RadicalSection 模块遍历五个 ZONES,渲染键盘分区图:

┌─────────────────┐
│ 1区  横区    🔴 │
│ ┌──┬──┬──┬──┬──┐│
│ │ G│ F│ D│ S│ A ││
│ └──┴──┴──┴──┴──┘│
├─────────────────┤
│ 2区  竖区    🟠 │
│ ┌──┬──┬──┬──┬──┐│
│ │ H│ J│ K│ L│ M ││
│ └──┴──┴──┴──┴──┘│
└─────────────────┘

每个分区卡片带对应区色的标题徽标键位方块,键位方块使用 zone.color + '33'(透明度 20%)的背景色和 zone.color + '88'(透明度 53%)的边框色,形成视觉层次。

8.3 分区口诀

📝 分区口诀
1区横起笔:王土大木工   GFDSA
2区竖起笔:目日口田山   HJKLM
3区撇起笔:禾白月人金   TREWQ
4区捺起笔:言立水火之   YUIOP
5区折起笔:已子女又纟   NBVCX

每个口诀用对应区色显示,帮助用户记忆键位分布。


9. 核心功能三:五笔规则学习模块

9.1 四大拆字规则

RulesSection 使用 RuleCard 组件展示五笔的四大核心规则:

规则 核心原则 反例对比
取大优先 取笔画最多的字根 “未”=二+小 ✓ vs 一+木 ✗
能散不连 优先散结构 “午”=十+十(散)✓
能连不交 优先相连结构 “天”=一+大(连)✓ vs 二+人(交)✗
兼顾直观 符合视觉习惯 “自”=丿+目(象形)✓

每个规则卡片用不同的颜色边框(绿、蓝、橙、紫)便于区分。

9.2 编码规则速查

🔑 编码规则速查
超过四码    取第1、2、3、末字根
刚好四码    取所有四码
三码字      取三码 + 末笔识别码
二码字      取两码 + 末笔识别码
一码字(键名) 连击四次键(如 金=QQQQ)
一级简码    按一次键 + 空格(如 我=Q)

这六条规则是五笔编码的核心法则,用户在学习过程中可以随时切换到规则页面速查。


10. ArkTS API 24 关键技术挑战与解决方案

在开发过程中,我们遇到了多个 ArkTS 特有的技术挑战。以下是详细的踩坑与解决记录。

10.1 @Builder 内不能声明局部变量

错误代码

@Builder
ResultCard() {
  const entry: WubiEntry = this.currentEntry as WubiEntry  // ❌ 编译错误
  // ... 使用 entry ...
}

原因:ArkTS API 24 的 @Builder 函数体被编译器视为「模板片断」而非函数,不支持局部变量声明。

解决方案:将需要的值作为参数传入:

@Builder
ResultCard(entry: WubiEntry) {  // ✅ 通过参数传递
  // ... 直接使用 entry ...
}

// 调用时
this.ResultCard(this.currentEntry as WubiEntry)

10.2 @Builder 内不能使用 return 语句

错误代码

@Builder
ResultCard() {
  if (entry === null) return  // ❌ 编译错误:@Builder 内不允许 return
  // ...
}

原因:同 10.1,@Builder 不是普通函数,不能提前退出。

解决方案:在调用处做守卫判断:

if (this.currentEntry !== null) {
  this.ResultCard(this.currentEntry as WubiEntry)  // ✅ 调用前已确保非空
} else if (this.notFound) {
  this.NotFoundCard()
}

10.3 ForEach 必须提供 keyGenerator(第三个参数)

错误代码

ForEach(LV1, (item: WubiEntry) => {
  Text(item.char)
  // ...
})  // ❌ 缺少第三个参数(API 24 编译可能警告或报错)

原因:API 24 要求 ForEach 对对象数组必须提供显式的 keyGenerator 函数,以便框架高效追踪元素变化。

解决方案:始终提供第三个参数:

ForEach(LV1, (item: WubiEntry) => {
  Text(item.char)
  // ...
}, (item: WubiEntry) => item.char)  // ✅ 唯一且稳定的 key

10.4 不支持 for…in 遍历对象

错误代码

for (const k in LOOKUP) {  // ❌ API 24 不支持
  // ...
}

原因:ArkTS API 24 移除了 for...in 语法,统一使用 for (let i = 0; i < N; i++) 形式。

解决方案:改用索引遍历:

for (let i = 0; i < WUBI_DATA.length; i++) {
  const item = WUBI_DATA[i]
  // ...
}

10.5 不支持 JavaScript 标准库的部分函数

不支持的功能 影响 替代方案
setTimeout 无法直接实现延迟 使用 setInterval 模拟,或使用 @State + animateTo
... 展开运算符 无法合并对象/数组 显式逐字段复制,或用 Array.push + 循环
toLocaleString 无法格式化数字 手动拼接字符串
forEach 方法 无法遍历数组 使用 for 循环或 ForEach 组件
flexWrap 无法换行布局 使用 Scroll(ScrollDirection.Horizontal) 实现横向滚动

10.6 类型安全的强制转换

在从 Record<string, WubiEntry> 中取值时,由于 LOOKUP 返回的是 WubiEntry | undefined,我们需要显式类型断言:

const entry = LOOKUP[char]
if (entry !== undefined) {
  this.currentEntry = entry  // ✅ entry 是 WubiEntry,不是 WubiEntry | undefined
}

// 当传入 @Builder 时需要再次断言
this.ResultCard(this.currentEntry as WubiEntry)  // ✅ 因为 this.currentEntry 声明为 WubiEntry | null

11. 状态管理与数据流

11.1 @State 状态定义

struct Index {
  @State searchChar: string = ''           // 当前搜索的汉字
  @State selectedChar: string = ''         // 已选中的汉字
  @State currentEntry: WubiEntry | null = null  // 当前查询结果
  @State notFound: boolean = false         // 是否未找到
  @State activeTab: string = 'search'      // 当前激活的标签页
}

11.2 数据流图

用户输入 ──▶ onChange ──▶ doSearch(char) ──▶ LOOKUP[char]
                                                   │
                                        ┌──────────┴──────────┐
                                        ▼                    ▼
                                 currentEntry ≠ null    currentEntry = null
                                        │                    │
                                        ▼                    ▼
                                  ResultCard 渲染     NotFoundCard 渲染
                                        │
                                        ▼
                                 codeWithPlus(entry.code)

11.3 状态更新的粒度

ArkTS API 24 的 @State 监听粒度是对象引用级别——当 this.currentEntry = entry 被赋值时,所有依赖 this.currentEntry 的 UI 片段重新渲染。

这意味着如果未来需要实现「编辑字根」等复杂操作,需要创建新对象而非修改原对象字段:

// ❌ 不会触发 UI 更新
this.currentEntry.level = 2

// ✅ 会触发 UI 更新
this.currentEntry = { ...this.currentEntry, level: 2 }

12. UI 主题与深色设计

12.1 色彩体系

用途 色值 透明度 说明
页面背景 #0A1628 100% 深空蓝黑
卡片背景 #111D33 100% 略亮的卡片底色
卡片内嵌 #0D1A33 100% 字根卡片背景
主文字 #FFFFFF 100% 标题和主要内容
辅助文字 #AABBCC 100% 规则说明等
次要文字 #8899AA 100% 标签、副标题
暗提示文字 #556677 100% 分区名称等
占位文字 #556677 100% 输入框 placeholder

12.2 五区配色

1区横区(GFDSA):#E74C3C 🟢红 → 起笔横
2区竖区(HJKLM):#E67E22 🟠橙 → 起笔竖
3区撇区(TREWQ):#2ECC71 🟢绿 → 起笔撇
4区捺区(YUIOP):#3498DB 🔵蓝 → 起笔捺
5区折区(NBVCX):#9B59B6 🟣紫 → 起笔折

12.3 字体与间距

  • 大字:48px#FFFFFFFontWeight.Bold
  • 编码:24px#3498DBFontWeight.BoldfontFamily: 'Courier New'
  • 正文:12-14px#AABBCC#CCDDEE
  • 字根:28px#FFFFFFFontWeight.Bold

13. 常见问题与调试经验

13.1 真机调试技巧

问题:模拟器上正常,真机上字根卡片边框颜色缺失

原因:颜色值中的透明度写法 + '44' 在部分设备上表现不一致

解决:将透明度写为完整 8 位色值,如 #E74C3C#E74C3C70

13.2 滚动容器嵌套

问题SearchSectionTextInput 输入时键盘弹出导致布局挤压

原因:外层 Scroll 和内层 Scroll(SearchSection中的常用字) 嵌套,键盘弹出时框架无法正确计算高度

解决:内层 Scroll 指定 layoutWeight(1),外层 Scroll 不用 layoutWeight,改为固定比例

13.3 @State 更新的延迟

问题onChange 中连续调用 doSearch 时 UI 闪烁

原因:每次赋值 this.currentEntry = null; this.notFound = false 触发两次渲染

解决:使用 updateState() 风格,将相关状态组合在一个对象中(单文件可提升性暂未优化,但知道这个方向即可)

13.4 编码拼合函数的边界情况

codeWithPlus(code: string): string {
  if (code.length <= 1) return code  // 边界:单字符编码(如一级简码)
  let result = ''
  for (let i = 0; i < code.length; i++) {
    if (i > 0) result += ' + '
    result += code.charAt(i)
  }
  return result
}

边界情况:

  • codeWithPlus('J')'J'(单字符,不拼接)
  • codeWithPlus('JEG')'J + E + G'
  • codeWithPlus('')''(空字符串)

14. 项目总结与下一步规划

14.1 项目数据

指标 数值
核心文件 1 个(Index.ets)
总代码行数 910 行
内置汉字 30+ 个
字根数据条目 ~120 条
@Builder 组件数 8 个
页面模块 3 个(查字/字根/规则)
开发周期 约 5 小时

14.2 学到的主要技术点

  1. ArkTS 语法规范:@Builder 的限制与最佳实践、ForEach 的 keyGenerator 必要性
  2. 数据模型设计:面向渲染的数据结构、接口分层、JSON 模拟数据的取舍
  3. 状态管理:@State 的基本使用、条件渲染、数据流设计
  4. UI 布局:Row/Column 弹性布局、Scroll 滚动、颜色透明度渲染
  5. 类型系统:联合类型(| null)、类型断言(as)、Record 字典

14.3 可能的扩展方向

如果要将这个工具完善为正式产品,以下方向值得探索:

  1. 字库扩充:接入完整 GB2312(6763 字)或 Unicode CJK 字库
  2. 在线搜索:接入五笔字典 API,支持不在本地字库的汉字
  3. 练习模式:随机出题,用户输入编码,自动判对
  4. 拆字动画:逐字根动画展示拆解过程,提升学习体验
  5. 多端适配:适配平板(平板显示键盘分区横向排列)和折叠屏
  6. 词库联想:输入编码显示候选字列表(仿真实输入场景)
  7. 用户词库:用户可自定义添加字根拆解,共享社区词库

14.4 给 HarmonyOS 开发者的建议

  • 大胆用 @Builder:虽然是 API 24 的新特性,但它确实是 ArkTS 组件化的核心武器,掌握它的限制比绕开它更重要
  • 从单文件开始:不要一开始就追求模块拆分,把全部逻辑放在一个文件中,跑通后再重构
  • 重视模拟数据:好的 mock 数据能覆盖大部分 UI 状态,减少开发中的「数据未到」等待
  • 利用颜色做分区:在需要展示分类信息时,颜色是比文字更高效的传达方式

附录 A:完整代码结构参考

本文对应源码位于 entry/src/main/ets/pages/Index.ets,结构如下:

Lines  1-  7:注释、版权声明
Lines  8- 29:三个接口定义(RadicalPart / WubiEntry / ZoneInfo)
Lines 31- 37:键盘分区常量 ZONES(5 区)
Lines 40-393:五笔字根数据 WUBI_DATA(~30 汉字)
Lines 397-414:工具函数 zoneColor / zoneName
Lines 416-428:LOOKUP 字典构建函数
Lines 430-442:难度分组 + LV1/LV2/LV3 数组
Lines 447-495:Index struct + build 方法(整体布局)
Lines 497-509:TabBtn @Builder
Lines 511-623:SearchSection @Builder + doSearch 方法
Lines 625-637:doSearch 方法
Lines 639-653:NotFoundCard @Builder
Lines 655-738:ResultCard @Builder
Lines 740-753:codeWithPlus 方法
Lines 755-822:RadicalSection @Builder
Lines 824-876:RulesSection @Builder
Lines 878-893:RuleCard @Builder
Lines 895-910:CodeRuleRow @Builder

附录 B:参考资源

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐