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

鸿蒙原生开发——从零构建倒数日追踪器

一、引言

人是靠期待活着的。生日、纪念日、旅行、毕业、节日——这些未来事件给我们时间感,让平凡的日常有了方向。"倒数日"这种 App 之所以流行,原因在于它把抽象的时间变成了具象的数字:"还有 3 天"比"下周三"更有紧迫感,"已过 12 天"比"两周前"更有纪念意义。

从技术角度看,倒数日涉及的核心问题是日期运算——两个日期之间相差多少天、今天是哪个日期、如何判断某个事件是将来还是过去、如何按距离今天的远近排序。这些运算不依赖后端,全部可以在前端用 JavaScript 的 Date API 完成。

本文将用 ArkUI 从零构建一个倒数日追踪器。功能包括:添加事件(名称 + 图标 + 目标日期)、自动计算剩余天数、四色距离标记(今天/明天红色、3 天内品红、7 天内蓝色、更远绿色)、已过事件灰色标记、自动按距离排序(最近的排最前)。配色严格避免了黄色系(红/品红/蓝/绿四色方案),确保所有文字与背景保持足够对比度。

阅读完本文,你将能够:

  • 使用DateAPI 进行日期差值计算
  • 实现四色距离标记系统(根据剩余天数动态着色)
  • 构建按距离自动排序的列表
  • 处理"已过事件"的特殊显示逻辑
  • 构建图标选择器 + 日期输入的表单弹窗

二、数据模型与日期运算

2.1 事件实体

interfaceCountdownEvent{id:number;name:string;icon:string;date:string;// YYYY-MM-DD}

日期用YYYY-MM-DD格式存储——与日记本相同策略。8 个预设图标涵盖常见事件类型:生日🎂、纪念日💍、毕业🎓、旅行✈️、搬家🏠、节日🎄、庆祝🎉、自定义📅。

2.2 核心日期函数

两个函数构成日期系统的全部基础:

functiontodayStr():string{constd=newDate();return`${d.getFullYear()}-${(d.getMonth()+1).toString().padStart(2,'0')}-${d.getDate().toString().padStart(2,'0')}`;}functiondaysBetween(from:string,to:string):number{constf=newDate(from);constt=newDate(to);returnMath.floor((t.getTime()-f.getTime())/(1000*60*60*24));}

todayStr()返回当天日期的字符串(如2026-06-11),用于构建"今天"的参照点。

daysBetween()计算两个日期之间相差的整天数。核心公式:(t.getTime() - f.getTime()) / (1000 * 60 * 60 * 24)getTime()返回毫秒时间戳,差值除以 86400000(一天的毫秒数)得到天数。Math.floor向下取整——因为我们只关心完整的"天",不关心小时和分钟。

正值表示目标日期在未来(“还有 N 天”),负值表示目标日期已过(“已过 N 天”),零表示今天。

2.3 动态排序

事件列表按距今天的距离排序——最近的排在最前:

sortedEvents():CountdownEvent[]{return[...this.events].sort((a,b)=>{constda=daysBetween(todayStr(),a.date);constdb=daysBetween(todayStr(),b.date);if(da<0&&db>=0)return1;// a 已过,b 将来 → a 排后if(db<0&&da>=0)return-1;// b 已过,a 将来 → a 排前returnda-db;// 都将来或都已过 → 按距离});}

排序规则:

  1. 将来的事件排在已过事件前面
  2. 将来事件按距离近 → 远排列(今天排第一,28 天后排最后)
  3. 已过事件按距离近 → 远排列(昨天排最前,1 年前的排最后)

用户打开页面后,最紧迫的事件(今天、明天)自然出现在第一位,不需要手动调整。

三、四色距离标记

3.1 颜色设计

用四种颜色标记事件的距离:

距离颜色色值语义
已过灰色#888899“这件事已经发生了”
0-1 天红色#FF4D4F“就是今天/明天!紧迫”
2-3 天品红#EB2F96“快到了,做好准备”
4-7 天蓝色#1677FF“还有一周,心里有数”
8 天以上绿色#52C41A“还早,轻松等待”

四种颜色构成了一个情感梯度:红色 = 紧迫感,品红 = 关注,蓝色 = 平常,绿色 = 从容。用户不需要阅读"还有 X 天"的文字,光看颜色就能感知每件事的紧迫程度。

注意这里完全避免了黄色/金色——红色 → 品红 → 蓝色 → 绿色的渐变中,没有黄色参与。品红(#EB2F96)在 2-3 天的位置替代了本来可能使用橙色/黄色的角色,且白字对比度远优于黄色。

3.2 动态文字标签

除了颜色,每个事件还有对应的文字标签:

proximityLabel(days:number):string{if(days<0)return`已过${Math.abs(days)}`;if(days===0)return'今天!';if(days===1)return'明天';return`还有${days}`;}

"今天!“和"明天"是两个特殊情况——它们给人最强的紧迫感和期待感,所以用特殊的文字而非简单的"还有 0 天"或"还有 1 天”。感叹号增加了情感色彩——今天发生的事值得一个感叹号。

3.3 半透明背景色

每个事件卡片的图标区域也有对应的半透明背景色:

proximityBg(days:number):string{if(days<0)return'#88889915';if(days<=1)return'#FF4D4F15';if(days<=3)return'#EB2F9615';if(days<=7)return'#1677FF15';return'#52C41A15';}

15(十六进制)= 约 8% 不透明度。这是一个非常淡的背景色——刚好能感知到色相,但不会和白色卡片背景产生冲突。如果背景色太深(比如 30-50% 不透明度),会和卡片文字争夺视觉注意力。

四、事件管理

4.1 添加事件

点击右下角 FAB("添加事件"蓝色按钮)弹出底部表单,包含三个输入区:

图标选择器:8 个 emoji 图标排列成行。选中态蓝底浅蓝边框(#1677FF22+ 1.5vp 边框),未选中态透明。与日记本的心情选择器不同,这里用边框区分选中态(而非不透明度)——因为图标都需要完整辨认,不适合降低不透明度。

名称输入TextInput组件,占位文字"事件名称,如’生日派对’"。限制单行。

日期输入TextInput组件,占位文字"日期,如 2026-12-25"。使用自由文本输入而非 DatePicker 的原因是:DatePicker 选择未来几个月甚至几年的日期需要多次滑动,不如直接输入YYYY-MM-DD快。

底部两个按钮——取消(灰色)和确认添加(蓝色,输入为空时灰色禁用)。

4.2 删除事件

每条事件卡片右侧有 × 按钮。点击直接删除——与日记本的删除逻辑相同,“可见即确认”,不需要额外的确认弹窗。

五、UI 设计

5.1 深色标题栏 + 白色卡片列表

与记账本类似的布局架构:

  • 深色标题栏(#1a1a2e):标题"⏳ 倒数日" + 事件计数
  • 浅灰背景(#F2F3F5):白色事件卡片列表
  • 蓝色 FAB:右下角悬浮

5.2 事件卡片布局

每张卡片水平排列四个元素:

  1. 图标区(56×56vp 圆角方块,淡色背景):大号 emoji
  2. 信息区(flex 1):事件名称(加粗深色)+ 日期(浅灰小字)
  3. 天数标签:动态文字 + 动态颜色(红色/品红/蓝色/绿色/灰色)
  4. 删除按钮:浅灰 ×

卡片之间用 1vp 的细微间隙分隔,第一张卡片顶部与列表顶部对齐(borderRadius特殊处理)。

5.3 空状态

当事件列表为空时,显示空状态引导:📅 emoji + “还没有倒数事件” + “点击右下角 + 添加一个”。空状态是用户教育的一部分——告诉用户这个页面是做什么的、怎么开始使用。

六、完整代码结构

CountdownPage ├── Stack(根容器) │ ├── Column(主界面) │ │ ├── Row(标题栏:⏳ 倒数日 + N 个事件) │ │ └── Scroll(事件列表) │ │ ├── if 空态 → 空状态引导 │ │ └── ForEach → Row(事件卡片) │ │ ├── Column(图标 + 半透明色底) │ │ ├── Column(名称 + 日期) │ │ ├── Text(还有/已过 N 天,动态色) │ │ └── Text(删除 ×) │ ├── Button(FAB:"+ 添加事件") │ └── if showAdd → Column(底部弹窗) │ ├── Row(8 个图标选择) │ ├── TextInput(事件名称) │ ├── TextInput(日期 YYYY-MM-DD) │ └── Row(取消 + 确认添加)

七、总结

本文从零构建了一个倒数日追踪器。与前几篇的功能型应用不同,倒数日的核心是日期运算 + 视觉距离编码

核心要点回顾:

  1. 日期运算todayStr()返回当天日期字符串,daysBetween()计算两个日期的整天差。全部使用原生DateAPI,无需第三方库。

  2. 四色距离标记:红色(0-1 天)= 紧迫,品红(2-3 天)= 关注,蓝色(4-7 天)= 平常,绿色(8 天+)= 从容。已过事件灰色。颜色构成情感梯度,用户不需要读文字就能感知紧迫程度。

  3. 自动排序sortedEvents()将将来事件排在已过事件前面,同类事件按距离升序排列。用户打开页面后最近的事件自然出现在第一位。

  4. 配色安全:四色方案中完全没有黄色/金色——红色 → 品红 → 蓝色 → 绿色的情感梯度中,品红替代了传统方案中的橙色/黄色位置。所有颜色与白字对比度均达标。

  5. 动态标签:"今天!"和"明天"使用特殊文字而非数字,增加情感色彩和紧迫感。

  6. 图标选择器:用边框区分选中态(而非不透明度),因为所有图标都需要完整辨认。

倒数日是"小而美"的典型——一个界面、一个列表、几个事件卡片。但日期运算、距离排序、颜色编码、情感标签这些细节组合在一起,形成了一个用户愿意每天打开看的工具。

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

相关文章:

  • 从设计到量产:手把手拆解芯片内存测试(MBIST)与修复(BISR)的全流程
  • 百度网盘直链解析工具:技术侦探带你破解下载速度之谜
  • 从S32K1到S32K3:手把手教你迁移汽车MCU项目(基于Arm Cortex-M7实战)
  • AC7840芯片UART+DMA循环接收工程(IAR/Keil双环境验证)
  • 为什么你的MOS管在干燥冬天更容易挂?从极间电容和输入电阻角度拆解静电积累
  • 网络安全干货:护网行动实战经验分享
  • 如何用LinkSwift快速获取九大网盘直链下载地址:告别限速烦恼
  • 三亚市黄金回收白银回收铂金回收彩金回收靠谱门店TOP排行榜及联系方式地址电话+诚信店铺推荐 - 大熊猫898989
  • 告别舞台灯光盲区:用STM32F0单片机手把手实现DMX512信号解码(附完整代码)
  • 3分钟掌握手机号定位技术:免费开源工具让地理位置查询变得简单
  • 鸿蒙原生应用实战(五):编译构建与性能优化 —— 从开发到上架
  • 从收音机到Wi-Fi:串联RLC电路如何成为无线通信的“频率守门员”?
  • 荆门市黄金回收白银回收铂金回收彩金回收靠谱门店TOP排行榜及联系方式地址电话+诚信店铺推荐 - 大熊猫898989
  • Qdrant源码与算法
  • 荆州市黄金回收白银回收铂金回收彩金回收靠谱门店TOP排行榜及联系方式地址电话+诚信店铺推荐 - 大熊猫898989
  • 生产级多维聚合四大铁律:从pandas groupby到银行风控实战
  • CMake 015:日志级别全解析
  • Barlow字体技术深度解析:从加州公路标识到数字设计的变量革命
  • 从‘天书’到蓝图:一文读懂Gerber文件里每个层(.gbr)到底在告诉工厂什么
  • XGP存档提取终极指南:3分钟释放你的游戏进度自由
  • 百度网盘直链解析技术深度解析:绕过限速实现高速下载的技术实现
  • X79双路主板Win10开机卡Logo?富士康/广达平台专用DLL修复包
  • 百度网盘资源工具终极指南:3分钟学会一键获取提取码的完整方法
  • PyTorch工程化起点:可复现、可扩展、可交付的训练模板
  • 景德镇市黄金回收白银回收铂金回收彩金回收靠谱门店TOP排行榜及联系方式地址电话+诚信店铺推荐 - 大熊猫898989
  • AutoCAD里能拖拽选中的自定义直线插件(ObjectARX C++源码工程)
  • 2026年济南中职学校大揭秘:究竟哪个教学质量更胜一筹?
  • 深入DHT11单总线协议:用STM32 HAL库微秒级延时精准读取温湿度数据
  • 从一段DXF数据看懂CAD图元结构:手把手教你用VBA解析Polyline的组码含义
  • Vue.js从零到精通系列(六):组合式函数与逻辑复用——打造自己的 Hooks 工具箱