在这里插入图片描述

引言

中华文化博大精深,生肖、天干、五行是其中最具代表性的符号体系。示例 45「生肖查询」让用户输入出生年份,就能查询到对应的生肖(12 生肖之一)、天干(10 天干之一)、五行(金木水火土)和周岁年龄。这个应用的实现核心是查表映射——通过年份与生肖/天干/五行的固定映射关系,快速查询对应结果。

在技术层面,这个示例涉及 ArkTS 的几个关键知识点:const 常量数组作为映射表、非负取模运算(mod 函数)、TextInput 数字输入与校验、Row + Column 组合布局的卡片设计、以及多状态变量的独立更新。

1. 应用概述与功能

「生肖查询」页面自上而下分为:顶部返回栏、年份输入框、查询按钮、生肖/天干/五行三栏卡片、年龄卡片。

1.1 核心功能清单

  • 年份输入:通过 TextInput 输入出生年份(数字格式)。
  • 生肖查询:根据年份计算对应生肖(鼠、牛、虎…猪)。
  • 天干查询:根据年份计算对应天干(甲、乙、丙…癸)。
  • 五行查询:根据天干映射对应五行(木、火、土、金、水)。
  • 年龄计算:根据当前年份与输入年份的差值计算周岁。
  • 输入校验:检查年份是否为有效数字、范围是否在 1900 至当前年份之间。

1.2 技术要点一览

  1. 常量映射表ZODIACSTEMELEMENT 三个字符串数组作为查表数据源。
  2. 非负取模mod() 函数处理负数取模的边界情况。
  3. 年份到生肖/天干的映射公式(year - 4) % 12(year - 4) % 10
  4. 动态三栏卡片Row + 三个 ColumnDivider 分隔,展示三个查询结果。
  5. 独立状态更新:生肖、天干、五行、年龄各用独立的 @State 变量。

2. 核心知识点

2.1 三个常量映射表

const ZODIAC: string[] = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪'];
const STEM: string[] = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'];
const ELEMENT: string[] = ['木', '木', '火', '火', '土', '土', '金', '金', '水', '水'];
  • ZODIAC:12 生肖,索引 0=鼠、1=牛…11=猪。
  • STEM:10 天干,索引 0=甲、1=乙…9=癸。
  • ELEMENT:10 天干对应的五行(每个天干对应一个五行)。甲=木、乙=木、丙=火、丁=火、戊=土、己=土、庚=金、辛=金、壬=水、癸=水。

三个数组都是模块级 const,在组件外部定义,不随组件实例变化。

2.2 生肖映射公式

生肖的映射关系基于年份与索引的对应:

  • 公元 4 年是鼠年(索引 0)。
  • 公式:(year - 4) % 12 得到生肖索引。

例如:

  • 2024 年:(2024 - 4) % 12 = 2020 % 12 = 4 → ZODIAC[4] = ‘龙’
  • 2000 年:(2000 - 4) % 12 = 1996 % 12 = 4 → ZODIAC[4] = ‘龙’
  • 1996 年:(1996 - 4) % 12 = 1992 % 12 = 0 → ZODIAC[0] = ‘鼠’

2.3 天干映射公式

天干的映射关系同理:

  • 公元 4 年是甲年(索引 0)。
  • 公式:(year - 4) % 10 得到天干索引。

例如:

  • 2024 年:(2024 - 4) % 10 = 2020 % 10 = 0 → STEM[0] = ‘甲’
  • 1990 年:(1990 - 4) % 10 = 1986 % 10 = 6 → STEM[6] = ‘庚’

2.4 五行映射

五行通过天干的索引直接映射(使用 ELEMENT[stemIdx])。天干与五行的对应关系:

  • 甲、乙 → 木
  • 丙、丁 → 火
  • 戊、己 → 土
  • 庚、辛 → 金
  • 壬、癸 → 水

2.5 mod 函数:非负取模

mod(a: number, b: number): number {
  const r: number = a % b;
  return r < 0 ? r + b : r;
}

JavaScript 的 % 运算符对负数返回负数结果:(-1) % 12 = -1。但作为数组索引需要非负值。mod 函数在余数为负时加上除数,确保结果在 [0, b) 范围内。

例如:mod(-1, 12) = -1 + 12 = 11,对应「猪」。

在正常年份范围内(1900-当前年份),year - 4 不会为负数,所以 mod 函数实际上不会触发负数分支。但作为防御性编程,处理了边界情况。

2.6 query:查询逻辑

query(): void {
  const year: number = parseInt(this.yearText);
  if (Number.isNaN(year)) {
    promptAction.showToast({ message: '请输入有效年份' });
    return;
  }
  const curYear: number = new Date().getFullYear();
  if (year < 1900 || year > curYear) {
    promptAction.showToast({ message: '请输入 1900~' + curYear + ' 之间的年份' });
    return;
  }
  const zodiacIdx: number = this.mod(year - 4, 12);
  const stemIdx: number = this.mod(year - 4, 10);
  this.zodiac = ZODIAC[zodiacIdx];
  this.stem = STEM[stemIdx];
  this.element = ELEMENT[stemIdx];
  this.ageText = (curYear - year) + ' 岁';
}

查询流程:

  1. 解析年份parseInt(this.yearText) 解析用户输入。
  2. 有效性检查Number.isNaN(year) 拦截非数字输入。
  3. 范围检查:检查年份是否在 1900 到当前年份之间。
  4. 计算索引mod(year - 4, 12)mod(year - 4, 10)
  5. 查表赋值:从映射表中获取结果,分别赋值给四个 @State 变量。

2.7 @State 状态变量

@State yearText: string = '';
@State zodiac: string = '--';
@State stem: string = '--';
@State element: string = '--';
@State ageText: string = '--';
  • yearText:输入框文本,初始为空。
  • zodiac/stem/element:查询结果,初始为 -- 占位符。
  • ageText:年龄文本,初始为 --

四个结果变量独立更新,互不影响。

3. 源码逐段解析

3.1 常量映射表定义

三个 const 数组定义在组件外部。这是因为它们是模块级的常量,不需要组件实例化。如果定义在组件内部(private),每次组件创建都会重新初始化,效率较低。

3.2 输入与查询

TextInput 使用 type(InputType.Number) 弹出数字键盘,onChange 实时更新 yearText。查询按钮点击触发 query() 方法。

3.3 三栏卡片布局

Row() {
  Column() {
    Text('生肖')
    Text(this.zodiac).fontSize(28).fontColor('#1a6cff')
  }.layoutWeight(1)
  Divider().vertical(true).height(52)
  Column() {
    Text('天干')
    Text(this.stem).fontSize(28).fontColor('#e03131')
  }.layoutWeight(1)
  Divider().vertical(true).height(52)
  Column() {
    Text('五行')
    Text(this.element).fontSize(28).fontColor('#0aa869')
  }.layoutWeight(1)
}

三个 ColumnlayoutWeight(1) 等宽分布,Divider 垂直分隔。每个栏目标题(灰色小字)+ 结果(彩色大字)。三个结果使用不同颜色区分:生肖蓝、天干红、五行绿。

3.4 年龄卡片

独立的卡片展示年龄,使用 Row 布局:左侧标签「年龄」,右侧年龄文本。

3.5 整体风格

白色圆角卡片 + 浅灰背景 + 主题蓝/红/绿三色点缀,与系列其他示例一致。

4. 关键实现细节分析

4.1 查表映射 vs 计算映射

生肖和天干使用「查表映射」而非「计算映射」。虽然存在数学公式可以直接计算(如 (year - 4) % 12),但查表法更直观、易于扩展。如果未来需要调整映射规则(如加入闰月修正),只需修改数组内容。

4.2 五行映射的二次查表

五行不是直接从年份计算的,而是通过天干索引二次查表:ELEMENT[stemIdx]。这种「年份 → 天干 → 五行」的两步映射符合中华文化中年份与五行的关系——五行是天干的属性。

4.3 输入校验的防御层次

三层校验保护:

  1. 非空检查Number.isNaN 检查输入是否为有效数字。
  2. 范围检查year < 1900 || year > curYear 检查年份是否在合理范围。
  3. 计算防御mod() 函数处理负数取模(虽然实际不会触发)。

4.4 占位符设计

未查询时,所有结果显示 --,给用户明确的「无数据」提示。查询后替换为实际值。这种「占位符 → 实际值」的模式比隐藏/显示更友好。

4.5 年龄计算的简化

ageText = (curYear - year) + ' 岁' 是一个简化的年龄计算,没有考虑生日。如果当前日期在生日之前,实际年龄应该比计算值小 1 岁。但作为生肖查询的附属功能,这种简化是可接受的。

5. 运行效果与操作指南

5.1 运行步骤

  1. 从入口页导航到「生肖查询」页面。
  2. 在输入框中输入出生年份(如 2000)。
  3. 点击「查询」按钮。
  4. 查看生肖、天干、五行和年龄结果。

5.2 使用场景

  • 生肖查询:知道自己的生肖属性。
  • 文化学习:了解天干地支五行等传统文化。
  • 八字排盘:作为更复杂命理计算的基础。

6. 可扩展方向

6.1 添加农历生日转换

支持公历生日转农历生日,再计算生肖和八字。

6.2 添加八字排盘

根据年、月、日、时计算八字(年月日时的天干地支组合)。

6.3 添加生肖详情

点击生肖查看生肖详情(如性格特征、运势等)。

6.4 添加历史年份对照

显示 1900 至今年的生肖/天干对照表。

7. 常见问题与调试技巧

7.1 查询结果显示 --

检查 query() 是否执行。确认输入的年份通过了所有校验。

7.2 生肖/天干计算错误

检查 mod(year - 4, 12) 的结果。确认年份索引的基准(公元 4 年为鼠年/甲年)。

7.3 五行结果不对

检查 ELEMENT[stemIdx] 是否正确。确认天干到五行的映射表 ELEMENTSTEM 的索引对应。

7.4 年龄计算偏差

如果当前日期在生日之前,实际年龄比显示的小 1 岁。如需精确计算,需要加入生日比较逻辑。

8. 总结

示例 45「生肖查询」用约 129 行代码,展示了 ArkTS 在「查表映射 + 卡片布局」场景下的实现。重点回顾:

  • 常量映射表:模块级 const 数组作为查表数据源。
  • 非负取模mod() 函数处理负数边界。
  • 输入校验:三层防御(非空、范围、防御性)。
  • 三栏卡片Row + Column + Divider 的经典布局模式。
  • 独立状态:每个查询结果用独立 @State 变量。

这些查表映射的技术在后续的单位换算、汇率计算等示例中会被复用。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐