当前位置: 首页 > news >正文

鸿蒙新特性:DatePicker 日期选择器——构建纪念日管理器

在移动端表单中,日期选择是最常见的输入场景之一。生日、纪念日、截止日期——这些都需要一个直观的日期选择组件。与日历视图(CalendarPicker)不同,滚轮式日期选择器更适合快速翻选年月日,特别适合选择出生日期、历史日期等需要跨越较大时间范围的场景。

HarmonyOS NEXT ArkUI 提供了 DatePicker 组件——一个滚轮式的日期选择器,用户通过上下滑动年/月/日三列滚轮来精确选择日期。本文将深入讲解 DatePicker 的 API 和使用细节,并构建一个"纪念日管理器"——支持日期选择、事件命名、倒计时/正计时计算和分类筛选。

关键词:HarmonyOS、ArkUI、DatePicker、日期选择器、纪念日、倒计时、日期计算

一、DatePicker 组件 API

1.1 基本用法

DatePicker({selected:this.pickDate}).onChange((value:DatePickerResult)=>{lety=value.year??newDate().getFullYear();letm=value.month??0;letd=value.day??1;this.pickDate=newDate(y,m,d);})

核心参数与属性:

参数/属性类型说明
selectedDate默认选中的日期
startDate可选日期范围的起始(可选)
endDate可选日期范围的结束(可选)
.onChange()callback选中日期变化时的回调(已标记为 deprecated)

1.2 DatePickerResult 的可选字段

DatePicker 的onChange回调接收一个DatePickerResult对象,包含三个字段:

interfaceDatePickerResult{year?:number;// 选中的年份(可能为 undefined)month?:number;// 选中的月份(0-11,0=一月)day?:number;// 选中的日期(1-31)}

重要:这三个字段都是可选的(number | undefined)。在构建Date对象时必须处理undefined的情况:

.onChange((value:DatePickerResult)=>{lety=value.year??newDate().getFullYear();letm=value.month??0;letd=value.day??1;this.pickDate=newDate(y,m,d);})

使用??(空值合并运算符)为undefined提供合理的默认值。不处理undefined会导致编译错误:Argument of type 'number | undefined' is not assignable to parameter of type 'number'

1.3 month 的索引问题

DatePickerResult.month返回的是0-based月份索引——即 0 代表一月,1 代表二月,…,11 代表十二月。这与 JavaScript 的Date构造函数中month参数的语义一致。

Date.getMonth()也返回 0-based 的月份,所以直接用于new Date(y, m, d)是正确的。然而在显示时需要加 1:

formatDate(date:Date):string{letm=(date.getMonth()+1).toString().padStart(2,'0');// 显示用 1-based:一月显示为 "01"returny.toString().concat('-').concat(m).concat('-').concat(d);}

1.4 onChange 的 deprecated 状态

在当前 API 版本中,DatePicker 的.onChange()被标记为deprecated。虽然仍然可以使用(不会导致编译错误,仅为警告),但未来版本可能会移除。由于 ArkUI 的 DatePicker 目前没有公开的替代回调 API(如onDateChange),现阶段继续使用.onChange()是唯一可行的方案。当官方提供替代 API 时,迁移也非常简单——只需修改回调方法名。

1.5 DatePicker vs CalendarPicker

这是读者容易混淆的两个组件:

维度DatePickerCalendarPicker
交互形态滚轮翻选(年月日三列)日历网格(月视图)
日期范围适合大跨度(几十年)适合近距选择(几个月内)
空间占用固定高度,可嵌入表单需要较大空间展示整月
典型场景出生日期、证件有效期日程安排、事件日期查询
视觉效果选中行高亮居中选中日期圆圈高亮

选择建议

  • 需要快速选择跨越几十年的日期(如出生年份选到 1980 年)→ 用DatePicker,滚轮翻选比翻日历快得多
  • 需要展示月度视图、查看某天是否有事件 → 用CalendarPicker

二、纪念日管理器的整体设计

2.1 页面架构

DatePickerPage ├── 标题栏 — "纪念日管理" + 事件计数 ├── 日期选择卡片 │ ├── DatePicker 组件(年月日三列滚轮) │ └── 格式化日期显示(含星期) ├── 添加事件卡片 │ ├── 事件名称输入框 │ └── "添加事件"按钮 └── 事件列表卡片 ├── 筛选标签(全部/即将到来/已过去) ├── 事件行(名称 + 日期 + 倒计时/正计时 + 删除) └── 空状态提示

2.2 数据类设计

classAnniversaryEvent{name:string;dateStr:string;// YYYY-MM-DD 格式,用于 Date 解析timestamp:number;constructor(name:string,dateStr:string,timestamp:number){this.name=name;this.dateStr=dateStr;this.timestamp=timestamp;}getDaysDiff():number{lettoday=newDate();today.setHours(0,0,0,0);leteventTime=newDate(this.dateStr);eventTime.setHours(0,0,0,0);letdiffMs=eventTime.getTime()-today.getTime();returnMath.floor(diffMs/(1000*60*60*24));}getDaysLabel():string{letdays=this.getDaysDiff();if(days>0)return'还有 '.concat(days.toString()).concat(' 天');if(days===0)return'今天';return'已过 '.concat(Math.abs(days).toString()).concat(' 天');}isUpcoming():boolean{returnthis.getDaysDiff()>=0;}isToday():boolean{returnthis.getDaysDiff()===0;}}

getDaysDiff()是核心计算方法。它将"今天"和"事件日期"的时间部分都归零(setHours(0,0,0,0)),只保留日期部分进行比较。毫秒差除以1000 * 60 * 60 * 24得到天数差,Math.floor()取整。

正数表示未来日期(“还有 X 天”),0 表示今天,负数表示过去的日期(“已过 X 天”)。

isUpcoming()判断事件是否即将到来。注意这里用的是>= 0——“今天"也算入"即将到来”,因为今天的事件确实还没有过去。

2.3 日期格式化

Demo 中实现了两种格式化方式:

存储格式formatDate):YYYY-MM-DD,用于dateStr字段。这个格式可以直接传给new Date()构造函数精确解析。

显示格式formatDisplay):中文日期 + 星期,例如"2026年7月8日 周三"。星期通过date.getDay()获取(0=周日,1=周一,…,6=周六),映射到中文星期名数组。

formatDisplay(date:Date):string{lety=date.getFullYear();letm=date.getMonth()+1;letd=date.getDate();letweekDays=['日','一','二','三','四','五','六'];letw=weekDays[date.getDay()];returny.toString().concat('年').concat(m.toString()).concat('月').concat(d.toString()).concat('日 周').concat(w);}

2.4 添加事件

addEvent():void{letname=this.eventName.trim();if(name.length===0){promptAction.showToast({message:'请输入事件名称',duration:1500});return;}letdateStr=this.formatDate(this.pickDate);letevent=newAnniversaryEvent(name,dateStr,Date.parse(dateStr));this.events=this.events.slice().concat(event);this.eventName='';promptAction.showToast({message:'已添加:'.concat(name),duration:1500});}
  1. trim()去空格后检查是否为空
  2. 将 DatePicker 选中的日期格式化为YYYY-MM-DD
  3. Date.parse(dateStr)获取时间戳(备用,实际计算使用new Date(dateStr)
  4. slice().concat(event)创建新数组更新@State

三、倒计时与正计时

3.1 天数计算

getDaysDiff():number{lettoday=newDate();today.setHours(0,0,0,0);leteventTime=newDate(this.dateStr);eventTime.setHours(0,0,0,0);letdiffMs=eventTime.getTime()-today.getTime();returnMath.floor(diffMs/(1000*60*60*24));}

setHours(0,0,0,0)是关键——它消除了时间部分对日期比较的影响。如果不归零时间部分,同一天的不同时刻(如上午 8 点和下午 6 点)会得到不同的天数差。

3.2 三种状态的视觉呈现

状态getDaysDiff()显示文字文字颜色
未来> 0“还有 X 天”蓝色#1677FF
今天=== 0“今天”绿色#52C41A
已过< 0“已过 X 天”灰色#BBBBCC
Text(event.getDaysLabel()).fontSize(14).fontColor(event.isToday()?'#52C41A':(event.isUpcoming()?'#1677FF':'#BBBBCC')).fontWeight(FontWeight.Bold)

三种颜色传达三种时间关系——蓝色表示期待(即将到来)、绿色表示正在发生(今天)、灰色表示回忆(已过去)。

四、分类筛选

4.1 三种视图

@StateactiveTab:string='all';// 'all' | 'upcoming' | 'past'

与上一篇 Checkbox 任务清单的筛选逻辑类似,纪念日管理器使用三态筛选:

activeTab含义筛选条件
'all'全部不过滤
'upcoming'即将到来isUpcoming() === true(含"今天")
'past'已过去isUpcoming() === false

4.2 删除时的筛选感知

deleteEvent方法需要感知当前筛选状态——用户可能在"即将到来"视图下删除某个事件,但该事件在完整列表中的索引与筛选后列表的索引不同。Demo 中采用"按名称+日期匹配删除"的策略:

deleteEvent(index:number):void{letsourceEvents=this.getFilteredEvents();lettarget=sourceEvents[index];// 从完整列表中移除匹配的事件letfullNew:AnniversaryEvent[]=[];letskipName=target.name;letskipDate=target.dateStr;for(leti=0;i<this.events.length;i++){if(this.events[i].name===skipName&&this.events[i].dateStr===skipDate){skipName='';// 只删除第一个匹配项}else{fullNew=fullNew.slice().concat(this.events[i]);}}this.events=fullNew;}

通过匹配name + dateStr在完整列表中定位要删除的事件,确保在任意筛选视图下都能正确删除。

五、交互流程演示

5.1 选择日期

进入页面,DatePicker 显示当前日期。上下滑动年、月、日三列滚轮来改变日期。格式化显示区实时更新——例如选择 2026 年 12 月 25 日,显示"2026年12月25日 周五"。

5.2 添加事件

在输入框中输入"圣诞节",点击"添加事件"。Toast 提示"已添加:圣诞节"。事件列表出现一条记录:名称"圣诞节"、日期"2026-12-25"、倒计时"还有 170 天"(蓝色)。

再添加一个已过去的日期——将 DatePicker 调到"2026-01-01",输入"元旦"。倒计时显示"已过 188 天"(灰色)。

5.3 筛选视图

点击"即将到来"标签——列表只显示未来的事件(包括今天)。元旦(已过 188 天)被隐藏。

点击"已过去"标签——列表只显示过去的事件。圣诞节被隐藏,只看到元旦。

点击"全部"标签——恢复显示所有事件。

5.4 删除事件

点击某条事件右侧的红色"删除"按钮。Toast 提示"已删除",该事件从所有视图中消失。标题栏的事件计数减 1。

5.5 今日事件

将 DatePicker 调到今天的日期,输入一个事件名称,点击"添加事件"。事件列表显示"今天"标签(绿色),与其他"还有 X 天"或"已过 X 天"形成对比。

六、实用扩展建议

6.1 重复提醒

当前 Demo 中的事件是一次性的——每个事件对应一个具体日期。实际应用通常需要重复提醒(每年生日、每月还款日等)。可以扩展AnniversaryEvent类增加repeat字段:

classAnniversaryEvent{repeat:string;// 'none' | 'yearly' | 'monthly'// ...}

对于"每年重复"的事件,计算天数差时取下一年的对应日期。

6.2 通知提醒

结合@ohos.notification能力,在纪念日到来时推送系统通知。可以在事件添加时计算剩余天数并设置定时提醒。

6.3 农历支持

中文纪念日场景中,农历日期非常常见(如春节、中秋节)。可以集成农历转换库,在 DatePicker 选中的公历日期旁边显示对应的农历日期。

七、总结

本文通过"纪念日管理器"这个实战案例,全面讲解了 ArkUI DatePicker 日期选择器组件的使用方法。核心知识点包括:

  1. DatePicker 基础 APIselected默认日期 +.onChange()回调获取选中结果
  2. DatePickerResult 可选字段处理year/month/day均为number | undefined,需用??提供默认值
  3. month 索引陷阱DatePickerResult.month为 0-based(0=一月),显示时需 +1
  4. onChange deprecated 警告:当前仍可使用,未来需要迁移到新 API
  5. 日期天数计算setHours(0,0,0,0)归零时间 + 毫秒差 → 天数整数
  6. 三种时间状态:未来(“还有 X 天”/蓝色)、今天(“今天”/绿色)、已过(“已过 X 天”/灰色)
  7. 筛选感知删除:按name + dateStr在完整列表中定位要删除的事件
  8. DatePicker vs CalendarPicker:交互形态(滚轮 vs 日历网格)和适用场景的差异

日期选择是移动端的核心输入方式之一。DatePicker 的滚轮交互让用户在海量的日期空间中快速定位——对于需要跨越数十年范围的日期选择(如出生日期),它比日历视图高效得多。配合日期计算和状态管理,开发者可以轻松构建纪念日、倒计时、事件规划等各种时间相关功能。


http://www.jsqmd.com/news/1152751/

相关文章:

  • 软件测试如何在面试中介绍自己的项目经验,多次面试碰壁后总结
  • MOSFET 关断失效排查:从栅极驱动到 PCB 布局的 5 个关键点
  • Orca:从状态预测到物理世界理解的AI新范式
  • PHP 反序列化链构造实战:从 DASCTF ezpop 题解到 3 种常见魔术方法利用
  • PCA主成分分析1--(矿相定向重构、高效协同浸出)
  • 靠谱的号卡随身wifi怎么选购
  • ChatGPT提示工程 × Midjourney V6图像生成:如何用3步精准控制构图/风格/细节(附27个经测试的黄金Prompt模板)
  • 新手量化工具试用清单:股票池回测提醒和复盘
  • 2026软件测试面试总结
  • AI编程助手(上)
  • 5个实战技巧带你快速掌握STM32嵌入式开发:从零到工业级控制系统
  • 进销存软件到底怎么影响小微企业的经营效率
  • 【大模型】跟着张量走一遍 VLM:图像如何变成 LLM 的 token?|多模态大模型专栏③
  • League-Toolkit 终极指南:英雄联盟自动化助手配置与使用完全攻略
  • 国家中小学智慧教育平台电子课本解析工具:数字化教学资源的高效管理方案
  • tmgm mt5快讯:人工智能领域多项动态集中出现,技术应用与政策场景持续推进
  • 同一个模型,只改“外壳“性能狂飙22倍,Agent的瓶颈根本不在模型本身
  • 电商竞品监控工具:不同场景的实用选择
  • 严控原料临期风险,锁住企业经营利润!
  • L9958与PIC24FJ128GA310直流电机控制方案详解
  • FRED应用:TMT MOBIE成像光谱仪的概念设计阶段杂散光分析
  • 【大数据毕业设计】基于分布式大数据的养老院服务质量分析系统的设计与实现 基于 Hadoop 的养老院入住数据挖掘与研判系统(源码+文档+远程调试,全bao定制等)
  • 文本相似度工程:余弦相似度只是开始,不是终点
  • 自动售货机点位选不对?三步教你找到黄金位置~YH
  • OpenWrt网络加速终极指南:Turbo ACC插件让你的路由器性能翻倍
  • 计算机毕业设计之基于Android的交通查询系统
  • 技术深度解析:如何实现AI绘画工作流的架构革新
  • Qt5.6.2 + SQLite 纯代码入门实战:从零搭建数据库管理小工具
  • 2026 AI短视频全链路实战教程:1天批量生产10条爆款视频,普通开发者也能实现内容创业!
  • SWIDERM身体护理怎么样