7、打造鸿蒙原生日历组件:自定义 UI + 数据交互(附实操案例与效果图)

传统 App 的日历大多笨重难用,鸿蒙 ArkTS 声明式开发让构建一个轻量、高颜值、可交互的日历变得异常简单。今天,我们从零手写一个支持切换月份的原生鸿蒙日历组件!


🎯 一、目标功能

  • ✅ 展示当前月份的日历网格
  • ✅ 点击左右按钮切换上/下个月
  • ✅ 高亮当前日期
  • ✅ 动态生成每月的天数布局

最终效果:

markdown 复制代码
< 2025年4月 >
日 一 二 三 四 五 六
      1  2  3  4  5
6  7  8  9 10 11 12
...

🧩 二、数据准备:生成日历网格

先封装一个生成指定年月的日历数据方法:

typescript 复制代码
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 渲染日历

🛠️ 三、编写日历组件 CalendarView

scss 复制代码
@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 状态管理 切换月份后,自动更新日历
动态列表渲染 使用 ForEachGrid 实现网格布局
响应式更新 无需手动刷新界面,状态变化即自动重绘
组件复用 CalendarView 可直接插入任何页面

📖 六、扩展思考

  • ✅ 支持点击某天触发回调(例如签到、打卡)
  • ✅ 加入节假日、农历显示
  • ✅ 集成天气预报在日历格子中(超酷)

📘 下篇预告

《鸿蒙动画开发实战:做一个会跳舞的按钮》------深入鸿蒙动画系统,打造灵动交互体验!


相关推荐
Brookty1 分钟前
【JavaEE】线程安全-内存可见性、指令全排序
java·开发语言·后端·java-ee·线程安全·内存可见性·指令重排序
智能化咨询12 分钟前
【Linux】【实战向】Linux 进程替换避坑指南:从理解 bash 阻塞等待,到亲手实现能执行 ls/cd 的 Shell
前端·chrome
Anson Jiang15 分钟前
浏览器标签页管理:使用chrome.tabs API实现新建、切换、抓取内容——Chrome插件开发从入门到精通系列教程06
开发语言·前端·javascript·chrome·ecmascript·chrome devtools·chrome插件
风象南18 分钟前
SpringBoot Jar包冲突在线检测
后端
掘金安东尼18 分钟前
黑客劫持:周下载量超20+亿的NPM包被攻击
前端·javascript·面试
程序员爱钓鱼20 分钟前
Go语言实战案例 — 项目实战篇:任务待办清单 Web 应用
后端·google·go
剑亦未配妥1 小时前
移动端触摸事件与鼠标事件的触发机制详解
前端·javascript
Devil枫2 小时前
鸿蒙深链落地实战:从安全解析到异常兜底的全链路设计
安全·华为·harmonyos
Cyan_RA92 小时前
SpringMVC @RequestMapping的使用演示和细节 详解
java·开发语言·后端·spring·mvc·ssm·springmvc
人工智能训练师7 小时前
Ubuntu22.04如何安装新版本的Node.js和npm
linux·运维·前端·人工智能·ubuntu·npm·node.js