HarmonyOs应用《重要日》开发第11篇 - 年视图组件
本文解析 ImportantDays 项目中年视图的两个组件YearCalendar负责整体年份网格布局和无限滚动BaseCalendar负责单月小日历的渲染和重要日标记。两个组件协作呈现完整的年视图日历体验。一、年视图整体设计年视图将一整年的 12 个月以小日历网格的形式展示用户可以快速浏览全年概况并通过颜色圆点识别哪些日期有重要日。组件协作关系CalendarPage └── YearCalendar (年视图容器) ├── 年份标题 └── Swiper LazyForEach └── Grid (3×4 月份网格) └── BaseCalendar × 12 (单月小日历)二、YearCalendar 组件组件定义ComponentV2exportstruct YearCalendar{Paramvm:CalendarVMCalendarVM.getInstance();ParamonSelectDate:(date:Date)void(){};LocalyearDataSource:YearDataSourcenewYearDataSource();LocalcurrentYear:numbernewDate().getFullYear();privateswiperController:SwiperControllernewSwiperController();}参数说明参数类型说明vmCalendarVM日历视图模型通过 Param 传入onSelectDate(date: Date) void日期选择回调yearDataSourceYearDataSource年份数据源Local 内部状态currentYearnumber当前显示年份swiperControllerSwiperControllerSwiper 控制器初始化aboutToAppear():void{this.yearDataSourcethis.vm.yearDataSource;this.currentYearthis.vm.selectDate.year();}在组件即将出现时从 VM 获取数据源和当前年份。build 方法build(){Column(){// 年份标题Row(){Text(${this.currentYear}年).fontSize(20).fontWeight(FontWeight.Bold).fontColor(#333333)}.width(100%).justifyContent(FlexAlign.Center).padding({top:8,bottom:12})// 月份网格 - Swiper LazyForEachSwiper(this.swiperController){LazyForEach(this.yearDataSource,(year:number){Grid(){ForEach([0,1,2,3,4,5,6,7,8,9,10,11],(month:number){GridItem(){BaseCalendar({year:year,month:month,startWeekday:this.vm.startWeekday})}},(month:number)${year}_${month})}.columnsTemplate(1fr 1fr 1fr).rowsGap(8).columnsGap(4).width(100%).height(100%).padding(4)},(year:number)year_${year})}.cachedCount(CALENDAR_SWIPER_COUNT).index(1).loop(false).indicator(false).onChange((index:number){this.handleYearSwiperChange(index);}).layoutWeight(1)}.width(100%).height(100%)}布局结构Column ├── Row (年份标题) └── Swiper └── LazyForEach └── Grid (3列) └── GridItem × 12 └── BaseCalendarGrid 配置3 列 4 行columnsTemplate(1fr 1fr 1fr)— 每行 3 个月共 4 行行间距rowsGap(8)— 月份之间的垂直间距列间距columnsGap(4)— 月份之间的水平间距月份网格布局┌────────┬────────┬────────┐ │ 1月 │ 2月 │ 3月 │ ├────────┼────────┼────────┤ │ 4月 │ 5月 │ 6月 │ ├────────┼────────┼────────┤ │ 7月 │ 8月 │ 9月 │ ├────────┼────────┼────────┤ │ 10月 │ 11月 │ 12月 │ └────────┴────────┴────────┘三、年视图无限滚动privatehandleYearSwiperChange(index:number):void{if(indexthis.yearDataSource.totalCount()-1){// 追加下一年constlastYearthis.yearDataSource.getData(this.yearDataSource.totalCount()-1);this.yearDataSource.addData(lastYear1);}elseif(index0){// 前插上一年constfirstYearthis.yearDataSource.getData(0);this.yearDataSource.addDataFromHead(firstYear-1);}constcurrentYearthis.yearDataSource.getData(index);this.currentYearcurrentYear;this.vm.selectDatethis.vm.selectDate.year(currentYear);}滚动逻辑滑到末尾追加下一年lastYear 1滑到开头前插上一年firstYear - 1更新状态同步currentYear和 VM 的selectDate滚动示例初始: [2025] [2026*] [2027] 滑到2027: [2025] [2026] [2027*] → 追加2028 → [2025] [2026] [2027*] [2028]四、BaseCalendar 组件BaseCalendar负责渲染单月的小日历是年视图中每个月份的独立单元。组件定义Componentexportstruct BaseCalendar{Propyear:number0;Propmonth:number0;PropstartWeekday:number0;privatevm:CalendarVMCalendarVM.getInstance();privatemanager:ImportantDayManagerImportantDayManager.getInstance();}注意使用 V1 装饰器BaseCalendar使用Component和PropV1而非ComponentV2和ParamV2。这可能是因为Prop在 V1 中是值拷贝适合简单类型参数小日历组件不需要响应式更新年视图切换时整体重渲染保持与可能存在的 V1 组件兼容build 方法build(){Column(){// 月份标题Text(${this.month1}月).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#333333).margin({bottom:4})// 星期标题行Row(){ForEach(WEEK_NAMES,(name:string){Text(name).fontSize(10).fontColor(#999999).layoutWeight(1).textAlign(TextAlign.Center)})}.width(100%)// 日期网格Grid(){ForEach(this.getDateList(),(dateModel:DateModel,index:number){GridItem(){this.dayItem(dateModel)}},(dateModel:DateModel,index:number)${this.year}_${this.month}_${index})}.columnsTemplate(1fr 1fr 1fr 1fr 1fr 1fr 1fr).rowsGap(2).width(100%)}.width(100%).padding(8)}布局结构Column ├── Text (月份标题如 3月) ├── Row (星期标题行) └── Grid (7列) └── GridItem × 42 └── dayItem与 MonthWeekCalendar 的差异特性MonthWeekCalendarBaseCalendar装饰器ComponentV2Component参数传递Param(引用)Prop(值拷贝)字体大小16vp10-14vp日期项高度52vp22vp选中背景有Circle 填充无重要日标记圆点 标题预览仅圆点点击交互有无五、日期列表生成privategetDateList():DateModel[]{constdatedayjs().year(this.year).month(this.month);constlist:DateModel[][];constfirstDaydate.date(1);constdaysInMonthdate.daysInMonth();letfirstDayWeekday:numberfirstDay.day();firstDayWeekday(firstDayWeekday-this.startWeekdayWEEK_DAYS)%WEEK_DAYS;// 上月填充for(letifirstDayWeekday-1;i0;i--){constprevDatefirstDay.subtract(i1,day);list.push(newDateModel(prevDate,false));}// 当月for(leti1;idaysInMonth;i){constdayDatedate.date(i);list.push(newDateModel(dayDate,true));}// 下月填充while(list.length42){constlastDatelist[list.length-1].dayjsObj;list.push(newDateModel(lastDate.add(1,day),false));}returnlist;}此方法与CalendarVM.getDateList()逻辑相同但BaseCalendar独立实现以减少对 VM 的依赖。六、日期项渲染BuilderdayItem(dateModel:DateModel){Stack({alignContent:Alignment.Center}){// 重要日标记点if(this.hasImportantDay(dateModel)){Circle({width:4,height:4}).fill(this.getFirstDayColor(dateModel)).position({x:50%,y:2})}Text(${dateModel.day}).fontSize(11).fontColor(this.getDayColor(dateModel))}.width(100%).height(22)}标记点位置.position({x:50%,y:2})重要日标记圆点定位在日期格的顶部中央4×4vp 的小圆点不影响日期数字的显示。日期颜色策略privategetDayColor(dateModel:DateModel):string{if(!dateModel.isCurrentMonth){return#CCCCCC;// 非当月 → 灰色}if(this.vm.isToday(dateModel.dayjsObj)){return#FF6B6B;// 今天 → 红色}if(this.hasImportantDay(dateModel)){returnthis.getFirstDayColor(dateModel);// 有重要日 → 重要日颜色}return#333333;// 普通 → 深灰}颜色优先级非当月 → 今天 → 有重要日 → 普通注意年视图没有选中状态因为年视图主要用于浏览选中操作在月视图中进行。七、重要日查询privatehasImportantDay(dateModel:DateModel):boolean{returnthis.manager.hasImportantDay(dateModel.dateStr);}privategetFirstDayColor(dateModel:DateModel):string{constdaysthis.manager.getDaysByDate(dateModel.dateStr);if(days.length0){returndays[0].color;}return#FF6B6B;}与MonthWeekCalendar相同通过ImportantDayManager的dayMap查询。八、从年视图到月视图的切换在CalendarPage中年视图选择日期后会切换到月视图YearCalendar({vm:this.vm,onSelectDate:(date:Date){this.vm.changeDate(dayjs(date));this.vm.changeViewType(ViewTypeEnum.MONTH);this.updateTitle();this.updateSelectedDays();}})切换流程用户在年视图中点击某月 ↓ BaseCalendar 的小日历不响应点击 但 Grid 的整体可以扩展此功能 ↓ 实际上年视图通过 onSelectDate 回调 ↓ VM 切换到月视图 ↓ CalendarPage 重新渲染为月视图九、性能分析渲染开销年视图一次渲染 12 个月的小日历每个小日历有 42 个日期格总日期格数12 × 42 504 个每个日期格1 个 Text 可能 1 个 CircleDOM 节点数约 1000性能优化LazyForEach年视图的 Swiper 只渲染可见页预渲染页通过cachedCount控制小字体小尺寸10-11vp 字体、4vp 圆点减少渲染像素无交互小日历不响应点击减少事件处理开销Map 查询dayMap提供 O(1) 查询十、总结YearCalendar和BaseCalendar的协作展示了组件分层设计YearCalendar管理年份级别的 Swiper 滚动和 Grid 布局BaseCalendar专注于单月小日历的渲染和标记职责分离容器组件管布局和状态叶子组件管渲染性能可控LazyForEach 小尺寸渲染确保流畅V1/V2 混用展示了 ArkUI V1 和 V2 组件可以共存年视图为用户提供了全年重要日的鸟瞰视角是月视图的有力补充。

相关新闻

掌控你的塔科夫世界:SPT-AKI Profile Editor存档修改器完全指南

掌控你的塔科夫世界:SPT-AKI Profile Editor存档修改器完全指南

掌控你的塔科夫世界:SPT-AKI Profile Editor存档修改器完全指南 【免费下载链接】SPT-AKI-Profile-Editor Программа для редактирования профиля игрока на сервере SPT-AKI 项目地址: https://gitcode.com/gh_…

2026/7/18 15:23:30阅读更多 →
VLA工程化实战:具身智能系统的分层架构与闭环产线设计

VLA工程化实战:具身智能系统的分层架构与闭环产线设计

1. 项目概述:这不是调个模型的事,是搭一条能自我进化的操作产线“具身操作 & VLA 实战 Pipeline(工程化指南)”——光看标题,很多人第一反应是:“哦,又一个用VLA模型做机器人抓取的demo”。…

2026/7/18 15:23:30阅读更多 →
MSP430 MCU实现3D图形:定点数优化与嵌入式GUI实战

MSP430 MCU实现3D图形:定点数优化与嵌入式GUI实战

1. 项目概述与核心价值在嵌入式开发领域,尤其是在消费电子、医疗设备或工业控制面板这类对功耗和成本极其敏感的应用中,我们常常面临一个看似矛盾的需求:如何在资源极其有限的微控制器(MCU)上,实现流畅、动…

2026/7/18 15:23:30阅读更多 →
最新量化工具推荐,先把核心问题放回流程阶段

最新量化工具推荐,先把核心问题放回流程阶段

工具推荐常常被当成一个答案,但在策略流程里,它更像是一个判断过程。如果还不知道使用者真正卡在哪个环节,推荐就只能停留在笼统层面。一个更可靠的起点,是先把问题本身说窄,再看工具是否能在既有体系中补上那一段缺口…

2026/7/18 16:21:44阅读更多 →
Spring知识梳理(4)

Spring知识梳理(4)

Spring知识梳理(4)作者:没有四次元口袋的蓝胖 日期:2026-07-16 标签:Java, Spring, AOP, 面向切面编程一、AOP 是什么 AOP(Aspect-Oriented Programming,面向切面编程) 是对 OOP 的补充。 OOP:纵…

2026/7/18 16:21:44阅读更多 →
Dante Cloud蓝绿部署:零downtime的服务更新方案

Dante Cloud蓝绿部署:零downtime的服务更新方案

Dante Cloud蓝绿部署:零downtime的服务更新方案 【免费下载链接】dante-cloud 🐉 Dante Cloud 国内首个支持阻塞式和响应式服务并行的微服务云原生基座。采用领域驱动模型(DDD)设计思想,以「高质量代码、低安全漏洞」为核心,高度模…

2026/7/18 16:21:44阅读更多 →
奔赴少年CIIU携首张迷你专辑高调回归 开启C-Tro Pop音乐新篇章

奔赴少年CIIU携首张迷你专辑高调回归 开启C-Tro Pop音乐新篇章

日前,泛领文化旗下新生代男子组合奔赴少年CIIU正式公开首张迷你专辑《Closer to You(靠近你)》的概念视频,同步上线专辑收录新曲《一步一步》,高调拉开了组合回归的序幕。 专辑向大众展示了专属于奔赴少年CIIU的音乐风…

2026/7/18 16:21:44阅读更多 →
2026年下半年量化工具评估,分阶段设置检查标准

2026年下半年量化工具评估,分阶段设置检查标准

在既有策略体系中评估新工具时,最容易出现的误区是把工具价值看成一个总分。可是策略流程本身由多个阶段组成,每个阶段面对的风险、假设和检查重点都不同。工具是否有增量,往往要看它在具体阶段中解决了什么。工具要跟着当前任务走一个阶段可…

2026/7/18 16:21:44阅读更多 →
ChatGPT真正强大的不是对话——而是这5个被官方刻意弱化的底层接口调用方式

ChatGPT真正强大的不是对话——而是这5个被官方刻意弱化的底层接口调用方式

更多请点击: https://codechina.net 第一章:ChatGPT真正强大的不是对话——而是这5个被官方刻意弱化的底层接口调用方式 OpenAI 官方文档长期聚焦于 /v1/chat/completions 这一高层对话接口,却对更灵活、更可控的底层能力保持低调。事实上&…

2026/7/18 16:19:44阅读更多 →
VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异

VSCode TypeScript 环境配置对比:全局安装 vs 项目本地安装的4个关键差异当你在VSCode中启动一个新的TypeScript项目时,第一个技术决策往往从安装方式开始。这个看似简单的选择——全局安装还是项目本地安装——实际上会深刻影响你的开发流程、团队协作和…

2026/7/18 10:49:13阅读更多 →
智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手

智慧树刷课插件:5分钟实现自动化学习的智能助手 【免费下载链接】zhihuishu 智慧树刷课插件,自动播放下一集、1.5倍速度、无声 项目地址: https://gitcode.com/gh_mirrors/zh/zhihuishu 智慧树刷课插件是一款专为智慧树在线教育平台设计的Chrome浏…

2026/7/18 8:49:08阅读更多 →
Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案

Steam创意工坊下载器WorkshopDL:跨平台游戏模组获取的终极解决方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在GOG或Epic Games Store购买了心仪的游戏…

2026/7/18 14:49:24阅读更多 →
从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则

从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则

更多请点击: https://kaifayun.com 第一章:从模糊意图到可执行指令:Claude PRD中Prompt Engineering与需求颗粒度的5级映射法则 在Claude驱动的产品需求文档(PRD)生成实践中,原始业务意图往往以自然语言片…

2026/7/18 0:00:14阅读更多 →
Cursor配置生成失效?3大隐藏陷阱+4行修复代码,资深工程师连夜整理的紧急补救清单

Cursor配置生成失效?3大隐藏陷阱+4行修复代码,资深工程师连夜整理的紧急补救清单

更多请点击: https://codechina.net 第一章:Cursor配置生成失效?3大隐藏陷阱4行修复代码,资深工程师连夜整理的紧急补救清单 Cursor 配置生成突然失效,是近期高频报障场景。表面看是 cursor.config.json 未更新或 LSP…

2026/7/18 0:00:14阅读更多 →
某智驾大牛创业

某智驾大牛创业

作者:钟声编辑:Mark出品:红色星际头图:智能驾驶图片据悉,国内某头部智驾公司端到端模型技术大牛Z投身创业,并且已经拿到融资。Z不仅是该头部公司内部最年轻的对标阿里P10级别技术负责⼈,更是业内…

2026/7/18 0:00:14阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/17 22:48:46阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/18 14:49:24阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/17 17:26:50阅读更多 →