
回复
传统 App 的日历大多笨重难用,鸿蒙 ArkTS 声明式开发让构建一个轻量、高颜值、可交互的日历变得异常简单。今天,我们从零手写一个支持切换月份的原生鸿蒙日历组件!
最终效果:
< 2025年4月 >
日 一 二 三 四 五 六
1 2 3 4 5
6 7 8 9 10 11 12
...
先封装一个生成指定年月的日历数据方法:
function generateCalendar(year: number, month: number): Array<number|null> {
const date = new Date(year, month - 1, 1);
const firstDay = date.getDay(); // 当月第一天是星期几
const daysInMonth = new Date(year, month, 0).getDate(); // 当月天数
const calendar: Array<number|null> = Array(firstDay).fill(null); // 填充空白
for (let i = 1; i <= daysInMonth; i++) {
calendar.push(i);
}
return calendar;
}
null
表示空白格子ForEach
渲染日历@Entry
@Component
struct CalendarView {
@State currentYear: number = new Date().getFullYear()
@State currentMonth: number = new Date().getMonth() + 1
@State calendarData: Array<number|null> = []
aboutToAppear() {
this.updateCalendar();
}
updateCalendar() {
this.calendarData = generateCalendar(this.currentYear, this.currentMonth);
}
prevMonth() {
if (this.currentMonth === 1) {
this.currentYear -= 1;
this.currentMonth = 12;
} else {
this.currentMonth -= 1;
}
this.updateCalendar();
}
nextMonth() {
if (this.currentMonth === 12) {
this.currentYear += 1;
this.currentMonth = 1;
} else {
this.currentMonth += 1;
}
this.updateCalendar();
}
build() {
Column() {
// 顶部标题与切换按钮
Row() {
Button('<').onClick(() => this.prevMonth())
Text(`${this.currentYear}年${this.currentMonth}月`)
.fontSize(22)
.fontWeight(FontWeight.Bold)
.margin({ left: 12, right: 12 })
Button('>').onClick(() => this.nextMonth())
}
.justifyContent(FlexAlign.Center)
.margin({ bottom: 20 })
// 星期标题
Row() {
['日','一','二','三','四','五','六'].forEach(day => {
Text(day)
.width('13%')
.textAlign(TextAlign.Center)
.fontSize(16)
.fontWeight(FontWeight.Medium)
})
}
.margin({ bottom: 10 })
// 渲染日历网格
Grid({
columns: 7,
space: 6
}) {
ForEach(this.calendarData, (day, index) => {
if (day === null) {
Text('')
.width('13%')
.height(40)
} else {
const isToday = day === new Date().getDate()
&& this.currentMonth === new Date().getMonth() + 1
&& this.currentYear === new Date().getFullYear();
Text(`${day}`)
.width('13%')
.height(40)
.textAlign(TextAlign.Center)
.backgroundColor(isToday ? '#aaddff' : 'transparent')
.borderRadius(8)
}
}, item => `${item}-${Math.random()}`)
}
}
.padding(20)
.alignItems(HorizontalAlign.Center)
}
}
技术点 | 说明 |
---|---|
@State 状态管理 |
切换月份后,自动更新日历 |
动态列表渲染 | 使用 ForEach 和 Grid 实现网格布局 |
响应式更新 | 无需手动刷新界面,状态变化即自动重绘 |
组件复用 | CalendarView 可直接插入任何页面 |
《鸿蒙动画开发实战:做一个会跳舞的按钮》——深入鸿蒙动画系统,打造灵动交互体验!