HarmonyOS应用《玄象》开发实战:LunarCalendar.getTodayHeavenlyStems 干支计算在首页的接入

📅 2026/7/26 23:08:20 👁️ 阅读次数 📝 编程学习
HarmonyOS应用《玄象》开发实战:LunarCalendar.getTodayHeavenlyStems 干支计算在首页的接入

阅读时长:约 19 分钟 | 难度:★★★★☆ | 篇章:第 3 篇 · 首页与功能导航 对应源码:entry/src/main/ets/common/utils/LunarCalendar.etsHeavenlyStems.ets

前言

玄象项目首页顶部标题栏的“甲辰年│肖龙“不是硬编码文本,而是通过LunarCalendar.getTodayGanZhi()实时计算的今日干支。这一功能背后是玄象项目LunarCalendar工具类与HeavenlyStems工具类的协同。本篇将深入剖析玄象项目首页干支数据的计算与展示链路:从LunarCalendar.getTodayGanZhi方法实现、HeavenlyStems.getYearGanZhi干支推算算法、aboutToAppear数据初始化,到@State绑定与 UI 展示。掌握这套干支计算接入方法论,您就能为任何 HarmonyOS 应用接入实时数据。

提示:干支计算是玄象项目的核心算法之一,涉及天干地支组合、五行属性、生肖推算等复杂逻辑。

一、干支数据接入链路

1.1 完整数据流

用户打开首页 ↓ HomePage.aboutToAppear() ↓ LunarCalendar.getTodayGanZhi() ↓ HeavenlyStems.getYearGanZhi(year) ↓ HeavenlyStems.getShengXiao(year) ↓ 返回 "甲辰年│肖龙" ↓ @State todayGanZhi = '甲辰年│肖龙' ↓ UI 渲染 Text(this.todayGanZhi)

1.2 首页接入代码

// HomePage.ets @State todayGanZhi: string = ''; aboutToAppear(): void { this.todayGanZhi = LunarCalendar.getTodayGanZhi(); const yiji = LunarCalendar.getTodayYiJi(); this.yiItems = yiji.yi; this.jiItems = yiji.ji; } build() { Column() { Row() { // ... Column({ space: 4 }) { Text('玄象') Text(this.todayGanZhi) // ← 展示干支 } } } }

二、LunarCalendar.getTodayGanZhi 方法

2.1 完整源码

static getTodayGanZhi(): string { const now = new Date(); const year = now.getFullYear(); const month = now.getMonth() + 1; const day = now.getDate(); const ganZhi = HeavenlyStems.getYearGanZhi(year); const shengXiao = HeavenlyStems.getShengXiao(year); return `${ganZhi}年 | 肖${shengXiao}`; }

2.2 方法分解

步骤操作结果
1new Date()获取当前时间
2now.getFullYear()2026
3HeavenlyStems.getYearGanZhi(2026)“丙午”
4HeavenlyStems.getShengXiao(2026)“马”
5字符串拼接“丙午年│肖马”

2.3 模板字符串

return `${ganZhi}年 | 肖${shengXiao}`;

玄象项目使用 ES6 模板字符串,将干支与生肖拼接为展示格式。

三、HeavenlyStems 工具类

3.1 完整源码

export class HeavenlyStems { static readonly STEMS: string[] = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸']; static readonly BRANCHES: string[] = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥']; static readonly SHENGXIAO: string[] = ['鼠', '牛', '虎', '兔', '龙', '蛇', '马', '羊', '猴', '鸡', '狗', '猪']; static getStem(index: number): string { return HeavenlyStems.STEMS[index % 10]; } static getBranch(index: number): string { return HeavenlyStems.BRANCHES[index % 12]; } static getYearGanZhi(year: number): string { const stemIndex = (year - 4) % 10; const branchIndex = (year - 4) % 12; return `${HeavenlyStems.STEMS[stemIndex]}${HeavenlyStems.BRANCHES[branchIndex]}`; } static getShengXiao(year: number): string { const index = (year - 4) % 12; return HeavenlyStems.SHENGXIAO[index]; } static getFiveElement(stem: string): string { const map: Record<string, string> = { '甲': '木', '乙': '木', '丙': '火', '丁': '火', '戊': '土', '己': '土', '庚': '金', '辛': '金', '壬': '水', '癸': '水' }; return map[stem] || ''; } }

3.2 数据常量

常量长度内容
STEMS10甲、乙、丙、丁、戊、己、庚、辛、壬、癸
BRANCHES12子、丑、寅、卯、辰、巳、午、未、申、酉、戌、亥
SHENGXIAO12鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪

3.3 干支推算算法

getYearGanZhi 方法
static getYearGanZhi(year: number): string { const stemIndex = (year - 4) % 10; const branchIndex = (year - 4) % 12; return `${HeavenlyStems.STEMS[stemIndex]}${HeavenlyStems.BRANCHES[branchIndex]}`; }

算法原理:公元 4 年是甲子年(天干索引 0 + 地支索引 0)。

year = 2026 stemIndex = (2026 - 4) % 10 = 2022 % 10 = 2 → "丙" branchIndex = (2026 - 4) % 12 = 2022 % 12 = 6 → "午" 结果:"丙午"
getShengXiao 方法
static getShengXiao(year: number): string { const index = (year - 4) % 12; return HeavenlyStems.SHENGXIAO[index]; }

算法原理:公元 4 年是鼠年(索引 0)。

year = 2026 index = (2026 - 4) % 12 = 2022 % 12 = 6 → "马"

3.4 五行属性映射

static getFiveElement(stem: string): string { const map: Record<string, string> = { '甲': '木', '乙': '木', '丙': '火', '丁': '火', '戊': '土', '己': '土', '庚': '金', '辛': '金', '壬': '水', '癸': '水' }; return map[stem] || ''; }

玄象项目使用Record<string, string>映射表存储天干与五行属性:

天干五行
甲、乙
丙、丁
戊、己
庚、辛
壬、癸

四、LunarCalendar 工具类

4.1 农历数据编码

private static readonly LUNAR_INFO: number[] = [ 0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // ... 1900-2100 年共 201 个 ];

玄象项目使用位编码存储农历年份信息:

0x04bd8 = 0b 0000 0100 1011 1101 1000 ↑ ↑↑↑↑ ↑↑↑↑↑↑↑↑↑↑↑ 闰月位置 12 个月份天数(30/29)

4.2 农历月份天数算法

static getLunarMonthDays(year: number, month: number): number { return (LunarCalendar.LUNAR_INFO[year - 1900] & (0x10000 >> month)) ? 30 : 29; }
  • 0x10000 >> month:移位到对应月份位。
  • &操作:判断该月是否为 30 天(1 表示 30 天,0 表示 29 天)。

4.3 农历月名与日名

static readonly MONTH_NAMES: string[] = [ '正月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '冬月', '腊月' ]; static readonly DAY_NAMES: string[] = [ '初一', '初二', ..., '三十' ];

五、aboutToAppear 中初始化数据

5.1 初始化时机

aboutToAppear(): void { this.todayGanZhi = LunarCalendar.getTodayGanZhi(); const yiji = LunarCalendar.getTodayYiJi(); this.yiItems = yiji.yi; this.jiItems = yiji.ji; }

玄象项目在aboutToAppear中同步初始化首页数据,确保 UI 首次渲染时数据已就绪。

5.2 同步 vs 异步

玄象项目getTodayGanZhi()同步方法,无需等待:

aboutToAppear 开始 ↓ getTodayGanZhi() ← 同步计算,毫秒级完成 ↓ 赋值给 @State ↓ build 首次渲染(数据已就绪)

六、@State todayGanZhi 绑定

6.1 状态定义

@State todayGanZhi: string = '';

6.2 UI 绑定

Text(this.todayGanZhi) .fontSize(14) .fontColor(Colors.TEXT_SECONDARY)

@State绑定让 UI 在数据变化时自动更新。

6.3 更新时机

  • 用户首次打开首页:aboutToAppear中初始化。
  • 页面从后台切到前台:onPageShow中刷新。
onPageShow(): void { this.todayGanZhi = LunarCalendar.getTodayGanZhi(); }

七、GetTodayYiJi 宜忌数据

7.1 方法调用

const yiji = LunarCalendar.getTodayYiJi(); this.yiItems = yiji.yi; this.jiItems = yiji.ji;

7.2 YiJi 接口

export interface YiJi { yi: string[]; ji: string[]; }

八、干支显示的视觉设计

8.1 视觉格式

丙午年│肖马
  • 字号:14vp
  • 颜色:Colors.TEXT_SECONDARY
  • 对齐:居中

8.2 符号设计

玄象项目使用竖线分隔干支与生肖,简洁大方。

九、干支计算的扩展

9.1 月干支

static getMonthGanZhi(year: number, month: number): string { const stemIndex = ((year - 4) * 2 + month) % 10; const branchIndex = (month + 2) % 12; return `${HeavenlyStems.STEMS[stemIndex]}${HeavenlyStems.BRANCHES[branchIndex]}`; }

9.2 日干支

static getDayGanZhi(year: number, month: number, day: number): string { const days = this.getDaysFromBase(year, month, day); const stemIndex = days % 10; const branchIndex = days % 12; return `${HeavenlyStems.STEMS[stemIndex]}${HeavenlyStems.BRANCHES[branchIndex]}`; }

9.3 时干支

static getHourGanZhi(dayGan: string, hour: number): string { const dayStemIndex = HeavenlyStems.STEMS.indexOf(dayGan); const stemIndex = (dayStemIndex % 5 * 2 + Math.floor(hour / 2)) % 10; const branchIndex = Math.floor((hour + 1) / 2) % 12; return `${HeavenlyStems.STEMS[stemIndex]}${HeavenlyStems.BRANCHES[branchIndex]}`; }

十、玄象项目首页数据接入总结

10.1 数据来源

数据来源方法类型
今日干支LunarCalendar.getTodayGanZhi()同步
今日宜忌LunarCalendar.getTodayYiJi()同步
中间状态@State变量响应式

10.2 数据流

数据(LunarCalendar)→ @State → UI(Text) 数据层 ← 纯函数,无副作用 状态层 ← @State 响应式 UI 层 ← 自动更新

总结

本篇以玄象项目首页干支计算为蓝本,深入剖析了数据从算法到 UI 的完整接入链路:从LunarCalendar.getTodayGanZhi方法、HeavenlyStems.getYearGanZhi干支推算算法、aboutToAppear数据初始化,到@State绑定与 UI 展示。掌握这套数据接入方法论,您就能为任何 HarmonyOS 应用接入实时计算数据。

下一篇:《30 · @State currentTab 选中态切换与图标着色》,将带您深入玄象项目首页底部导航栏的选中态交互。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • HarmonyOS 官方文档:@State 装饰器
  • HarmonyOS 官方文档:Text 组件
  • 干支纪年法:wikipedia.org/wiki/干支
  • 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net