鸿蒙NEXT开发案例:年龄计算
【引言】
本案例的目标是开发一款年龄计算器应用,该应用能够根据用户输入的出生日期,计算出用户的实际年龄、虚岁、星座、生肖等信息。同时,应用还将提供距离下次公历和农历生日的天数及星期等信息。为了实现这些功能,我们将使用ArkTS和ArkUI作为开发语言,并借助@nutpi/calendar-tool三方库来处理复杂的日历运算。
【环境准备】
电脑系统:windows 10
开发工具:DevEco Studio NEXT Beta1 Build Version: 5.0.3.806
工程版本:API 12
真机:mate60 pro
语言:ArkTS、ArkUI
三方库:calendar-tool
【应用结构与实现】
1. 数据模型:首先定义一个Info类,用于封装用户的基本信息,如公历和农历的年月日、星期、星座、生肖等。
2. 界面构建:应用界面主要由一个标题栏和多个展示区组成,每个展示区负责显示不同的信息,例如实际年龄、虚岁、星座等。界面布局采用了Flex布局,以确保良好的视觉效果和用户体验。
3. 逻辑处理:通过引入@nutpi/calendar-tool三方库,我们可以轻松地完成日期转换、星座计算等任务。此外,我们还需要编写一些辅助函数,如计算实际年龄、虚岁、距离下次生日的天数等。
4. 用户交互:为了让用户可以方便地输入自己的出生日期,我们在界面上添加了一个日期选择器,支持公历和农历之间的切换。当用户选择日期后,应用会自动更新所有相关信息。
【完整代码】
使用的三方库:ohpm install @nutpi/calendar-tool
参考:【
代码:
import calendar from "@nutpi/calendar-tool" // 导入日历工具 class Info { sYear: number = 0 // 公历年份 sMonth: number = 0 // 公历月份 sDay: number = 0 // 公历日期 week: number = 0 // 星期几(数字表示) weekZH: string = "" // 星期几(中文表示) date: string = "" // 日期字符串(公历) zodiac: string = "" // 星座 lYear: number = 0 // 农历年份 lMonth: number = 0 // 农历月份 lDay: number = 0 // 农历日期 isLeap: boolean = false // 是否为闰年 lMonthZH: string = "" // 农历月份(中文表示) lDayZH: string = "" // 农历日期(中文表示) gzYearZH: string = "" // 年干支(中文表示) gzMonthZH: string = "" // 月干支(中文表示) gzDayZH: string = "" // 日干支(中文表示) animal: string = "" // 生肖 term: string = "" // 节气 festival: string = "" // 节日 } @Entry // 入口组件 @Component // 组件装饰器 struct AgeCalculatorPage { @State season: string = '-' // 季节状态 @State realAge: number = 0 // 实际年龄 @State lunarAge: number = 0 // 虚岁 @State festival: string = '-' // 节日状态 @State weekday: string = '-' // 星期状态 @State isLunar: boolean = false // 是否为农历 @State zodiac: string = '-' // 星座状态 @State animal: string = '-' // 生肖状态 @State daysToNextGregorianBirthday: number = 0 // 距离下次公历生日的天数 @State daysToNextLunarBirthday: number = 0 // 距离下次农历生日的天数 @State dayOfWeekNextGregorianBirthday: number = 0 // 下次公历生日的星期几 @State dayOfWeekNextLunarBirthday: number = 0 // 下次农历生日的星期几 @State totalMonthsAlive: number = 0 // 总月数 @State totalDaysAlive: number = 0 // 总天数 @State totalHoursAlive: number = 0 // 总小时 @State gregorianBirthDate: string = '-' // 公历出生日期 @State lunarBirthDate: string = '-' // 农历出生日期 private selectedBirthDate: Date = new Date('1989-01-17') // 选定的出生日期 private weekdays: string[] = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'] // 星期数组 // 计算距离下次公历生日的天数 private calculateDaysToNextGregorianBirthday(birthDate: Date) { const nextBirthday = this.getNextBirthday(birthDate); // 获取下一个公历生日 this.daysToNextGregorianBirthday = Math.ceil((nextBirthday.getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)); // 计算天数差 } // 计算下次公历生日是星期几 private calculateNextGregorianBirthdayDayOfWeek(birthDate: Date) { const nextBirthday = this.getNextBirthday(birthDate); // 获取下一个公历生日 this.dayOfWeekNextGregorianBirthday = nextBirthday.getDay(); // 获取星期几 } // 计算在地球上的生活时间 private calculateEarthTime(birthDate: Date) { const currentDate = new Date(); // 当前日期 const years = currentDate.getFullYear() - birthDate.getFullYear(); // 计算年份差 const months = currentDate.getMonth() - birthDate.getMonth(); // 计算月份差 const days = currentDate.getDate() - birthDate.getDate(); // 计算日期差 let adjustedYears = years; // 调整后的年份 let adjustedMonths = months; // 调整后的月份 if (days < 0) { adjustedMonths -= 1; // 如果天数为负,月份减1 } if (months < 0) { adjustedYears -= 1; // 如果月份为负,年份减1 adjustedMonths += 12; // 月份加12 } this.totalMonthsAlive = adjustedYears * 12 + adjustedMonths; // 计算总月数 this.totalDaysAlive = Math.floor((currentDate.getTime() - birthDate.getTime()) / (1000 * 60 * 60 * 24)); // 计算总天数 this.totalHoursAlive = Math.floor((currentDate.getTime() - birthDate.getTime()) / (1000 * 60 * 60)); // 计算总小时 } // 获取季节 private getSeason(date: Date) { const springStart = new Date(date.getFullYear(), 1, 3); // 春季开始日期 const summerStart = new Date(date.getFullYear(), 4, 5); // 夏季开始日期 const autumnStart = new Date(date.getFullYear(), 7, 7); // 秋季开始日期 const winterStart = new Date(date.getFullYear(), 10, 7); // 冬季开始日期 // 判断当前日期属于哪个季节 if (date >= springStart && date < summerStart) { this.season = '春'; // 春季 } else if (date >= summerStart && date < autumnStart) { this.season = '夏'; // 夏季 } else if (date >= autumnStart && date < winterStart) { this.season = '秋'; // 秋季 } else { this.season = '冬'; // 冬季 } } // 计算下一个生日 private getNextBirthday(birthDate: Date): Date { const currentDate = new Date(); // 当前日期 let nextBirthday = new Date(currentDate.getFullYear(), birthDate.getMonth(), birthDate.getDate()); // 计算下一个生日 if (currentDate > nextBirthday) { nextBirthday.setFullYear(nextBirthday.getFullYear() + 1); // 如果当前日期已过生日,年份加1 } return nextBirthday; // 返回下一个生日 } // 计算实际年龄 private calculateRealAge(birthInfo: Info) { const today = new Date(); // 当前日期 let realAge = today.getFullYear() - birthInfo.sYear; // 计算实际年龄 // 判断是否需要减去一年 if (today.getMonth() < birthInfo.sMonth - 1 || (today.getMonth() === birthInfo.sMonth - 1 && today.getDate() < birthInfo.sDay)) { realAge--; // 如果当前日期在生日之前,实际年龄减1 } this.realAge = realAge; // 设置实际年龄 } // 计算虚岁 private calculateLunarAge() { const today = new Date(); // 当前日期 const lunarNewYear = new Date(today.getFullYear(), 1, 22); // 假设农历新年总是在公历2月22日 let lunarAge = this.realAge + 1; // 虚岁为实际年龄加1 // 判断是否需要减去一年 if (today < lunarNewYear) { lunarAge--; // 如果当前日期在农历新年之前,虚岁减1 } this.lunarAge = lunarAge; // 设置虚岁 } // 计算星座和生肖 private calculateZodiacAndAnimal(birthInfo: Info) { this.zodiac = birthInfo.zodiac; // 设置星座 this.animal = birthInfo.animal; // 设置生肖 } // 计算星期和节日 private calculateWeekdayAndFestival(birthInfo: Info) { this.weekday = birthInfo.weekZH; // 设置星期 this.festival = birthInfo.festival; // 设置节日 } // 计算下次生日 private calculateNextBirthdays(birthInfo: Info) { this.calculateDaysToNextGregorianBirthday(this.selectedBirthDate); // 计算下次公历生日的天数 this.calculateNextGregorianBirthdayDayOfWeek(this.selectedBirthDate); // 计算下次公历生日是星期几 let nextLunarBirthdayInfo: Info = calendar.getDateByLunar(new Date().getFullYear(), birthInfo.lMonth, birthInfo.lDay, false); // 获取下一个农历生日信息 // 如果当前日期已过农历生日,获取明年的农历生日信息 if (new Date() > new Date(nextLunarBirthdayInfo.date)) { nextLunarBirthdayInfo = calendar.getDateByLunar(new Date().getFullYear() + 1, birthInfo.lMonth, birthInfo.lDay, false); // 获取明年的农历生日信息 } // 计算距离下次农历生日的天数 this.daysToNextLunarBirthday = Math.ceil((new Date(nextLunarBirthdayInfo.date).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)); this.dayOfWeekNextLunarBirthday = nextLunarBirthdayInfo.week; // 设置下次农历生日的星期几 } // 构建方法 build() { Column() { // 创建列 Text("年龄计算")// 显示标题 .width('100%')// 设置宽度为100% .height(44)// 设置高度为44 .backgroundColor(Color.Orange)// 设置背景颜色为橙色 .textAlign(TextAlign.Center)// 设置文本居中 .fontColor(Color.White); // 设置字体颜色为白色 Scroll() { // 创建可滚动区域 Column() { // 创建列 Row() { // 创建行 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('周岁').fontSize(16).fontColor(Color.Gray) // 显示“周岁”文本 Text(`${this.realAge}`).fontSize(18).fontColor(Color.Black) // 显示实际年龄 } .width('200lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('公历出生').fontSize(16).fontColor(Color.Gray) // 显示“公历出生”文本 Text(this.gregorianBirthDate).fontSize(18).fontColor(Color.Black) // 显示公历出生日期 } .width('425lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 }.width('650lpx').margin({ top: '30lpx' }).justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 Row() { // 创建行 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('虚岁').fontSize(16).fontColor(Color.Gray) // 显示“虚岁”文本 Text(`${this.lunarAge}`).fontSize(18).fontColor(Color.Black) // 显示虚岁 } .width('200lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('农历出生').fontSize(16).fontColor(Color.Gray) // 显示“农历出生”文本 Text(this.lunarBirthDate).fontSize(18).fontColor(Color.Black) // 显示农历出生日期 } .width('425lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 }.width('650lpx').margin({ top: '30lpx' }).justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 Row() { // 创建行 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('星座').fontSize(16).fontColor(Color.Gray) // 显示“星座”文本 Text(this.zodiac).fontSize(18).fontColor(Color.Black) // 显示星座 } .width('200lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('下一个公历生日').fontSize(16).fontColor(Color.Gray) // 显示“下一个公历生日”文本 Text(`还有${this.daysToNextGregorianBirthday}天,那天是${this.weekdays[this.dayOfWeekNextGregorianBirthday]}`) .fontSize(18)// 显示下一个公历生日的天数和星期 .fontColor(Color.Black) } .width('425lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 }.width('650lpx').margin({ top: '30lpx' }).justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 Row() { // 创建行 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('生肖').fontSize(16).fontColor(Color.Gray) // 显示“生肖”文本 Text(this.animal).fontSize(18).fontColor(Color.Black) // 显示生肖 } .width('200lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('下一个农历生日').fontSize(16).fontColor(Color.Gray) // 显示“下一个农历生日”文本 Text(`还有${this.daysToNextLunarBirthday}天,那天是${this.weekdays[this.dayOfWeekNextLunarBirthday]}`) .fontSize(18)// 显示下一个农历生日的天数和星期 .fontColor(Color.Black) } .width('425lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 }.width('650lpx').margin({ top: '30lpx' }).justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 Row() { // 创建行 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('季节').fontSize(16).fontColor(Color.Gray) // 显示“季节”文本 Text(this.season).fontSize(18).fontColor(Color.Black) // 显示季节 } .width('200lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('出生当天节日').fontSize(16).fontColor(Color.Gray).padding({ left: 5, right: 5 }) // 显示“出生当天节日”文本 Text(this.festival || '-').fontSize(18).fontColor(Color.Black) // 显示节日,若无则显示‘-’ } .width('425lpx') // 设置宽度 .height('150lpx') // 设置高度 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆 .justifyContent(FlexAlign.Center) // 设置内容居中 }.width('650lpx').margin({ top: '30lpx' }).justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 Column() { // 创建列 Text(`您在地球生活了`).fontSize(16).fontColor(Color.Gray).margin({ top: '30lpx' }) // 显示“您在地球生活了”文本 Row() { // 创建行 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('总月数').fontSize(16).fontColor(Color.Gray) // 显示“总月数”文本 Text(`${this.totalMonthsAlive}`).fontSize(18).fontColor(Color.Black) // 显示总月数 } .width('200lpx') // 设置宽度 .height('120lpx') // 设置高度 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('总天数').fontSize(16).fontColor(Color.Gray) // 显示“总天数”文本 Text(`${this.totalDaysAlive}`).fontSize(18).fontColor(Color.Black) // 显示总天数 } .width('200lpx') // 设置宽度 .height('120lpx') // 设置高度 .justifyContent(FlexAlign.Center) // 设置内容居中 Column({ space: '5lpx' }) { // 创建列,设置间距 Text('总小时').fontSize(16).fontColor(Color.Gray) // 显示“总小时”文本 Text(`${this.totalHoursAlive}`).fontSize(18).fontColor(Color.Black) // 显示总小时 } .width('200lpx') // 设置宽度 .height('120lpx') // 设置高度 .justifyContent(FlexAlign.Center) // 设置内容居中 }.width('650lpx').justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 } .width('650lpx') // 设置宽度 .margin({ top: '30lpx' }) // 设置上边距 .justifyContent(FlexAlign.SpaceBetween) // 设置内容居中 .borderColor(Color.Gray) // 设置边框颜色 .borderWidth(1) // 设置边框宽度 .borderRadius(5) // 设置边框圆角 } }.width('100%').layoutWeight(1) // 设置宽度为100%,权重为1 Row() { // 创建行 Text(`请选择出生${this.isLunar ? '(农历)' : '(公历)'}:`).fontColor(Color.Orange).fontSize(18) // 显示选择出生日期的文本 Button('切换公历农历')// 显示切换按钮 .backgroundColor(Color.Orange)// 设置背景颜色为橙色 .margin({ top: 30, bottom: 30 })// 设置上下边距 .borderRadius(5)// 设置边框圆角 .onClick(() => { // 点击事件 this.isLunar = !this.isLunar // 切换公历农历状态 }) }.width('650lpx').justifyContent(FlexAlign.SpaceBetween) // 设置行的宽度和间距 DatePicker({ // 创建日期选择器 start: new Date('1900-1-1'), // 设置起始日期 end: new Date('2100-1-1'), // 设置结束日期 selected: this.selectedBirthDate // 设置选定的出生日期 }) .height('350lpx')// 设置高度 .disappearTextStyle({ color: Color.Gray, font: { size: '16fp', weight: FontWeight.Bold } })// 设置消失文本样式 .textStyle({ color: Color.Black, font: { size: '18fp', weight: FontWeight.Normal } })// 设置文本样式 .selectedTextStyle({ color: Color.Orange, font: { size: '26fp', weight: FontWeight.Regular } })// 设置选定文本样式 .lunar(this.isLunar)// 设置是否为农历 .onDateChange((value: Date) => { // 日期选择器变化时的处理 let birthInfo: Info = calendar.getDateBySolar(value.getFullYear(), value.getMonth() + 1, value.getDate()); // 获取出生日期信息 this.selectedBirthDate = value; // 设置选定的出生日期 //公历出生 this.gregorianBirthDate = `${birthInfo.sYear}年${birthInfo.sMonth}月${birthInfo.sDay}日` // 设置公历出生日期 //农历出生 this.lunarBirthDate = `${birthInfo.lYear}年${birthInfo.lMonthZH}${birthInfo.lDayZH}` // 设置农历出生日期 this.calculateRealAge(birthInfo); // 计算实际年龄 this.calculateLunarAge(); // 计算虚岁 this.calculateZodiacAndAnimal(birthInfo); // 计算星座和生肖 this.calculateWeekdayAndFestival(birthInfo); // 计算星期和节日 this.calculateNextBirthdays(birthInfo); // 计算下次生日 this.getSeason(this.selectedBirthDate); // 获取季节 this.calculateEarthTime(value); // 计算在地球上的生活时间 }) } .height('100%') // 设置高度为100% .width('100%') // 设置宽度为100% } }