HarmonyOS ArkTS 实战:实现一个校园课程表应用
项目效果
本文实现的是一个基于 HarmonyOS 和 ArkTS 的校园课程表应用。项目中使用 ArkUI 组件完成页面布局,通过 @State 管理课程数据,实现课程添加、星期筛选、课程分类、课程统计、课程删除和当日课程展示等功能。
最终运行效果如下:

页面主要包含以下内容:
- 顶部应用标题;
- 本周课程数量统计;
- 当前星期课程数量统计;
- 当前筛选星期展示;
- 课程名称输入框;
- 任课教师输入框;
- 上课地点输入框;
- 上课时间输入框;
- 课程类型选择;
- 星期切换按钮;
- 课程列表展示;
- 单条课程删除;
- 清空当天课程;
- 空课程状态提示;
- 页面整体采用 ArkUI 声明式布局。
本文重点是演示如何在 HarmonyOS 项目中使用 ArkTS 和 ArkUI 实现一个完整的校园学习工具类单页面应用。项目代码主要写在 entry/src/main/ets/pages/Index.ets 文件中,适合作为 HarmonyOS ArkTS 入门到进阶之间的练习案例。
为了避免文章检测时出现链接占比过高的问题,本文不直接放图片链接。发布时可以在 CSDN 编辑器中手动插入一张应用运行总效果图。
前言
在校园生活中,课程表是一个非常实用的功能。学生每天都需要知道今天有哪些课、什么时候上课、在哪个教室上课、任课教师是谁。如果课程信息分散在聊天记录或纸质表格里,查找起来并不方便。
从应用开发角度来看,课程表项目非常适合作为 HarmonyOS ArkTS 的练习案例。它不依赖后端接口,也不需要复杂数据库,但可以完整覆盖页面布局、输入框绑定、按钮点击、数组管理、列表渲染、条件筛选和状态刷新等基础内容。
本文基于 HarmonyOS 和 ArkTS 实现一个校园课程表应用。用户可以输入课程名称、任课教师、上课地点和上课时间,选择课程类型后添加课程记录。页面可以按照星期筛选课程,也可以统计本周课程数量和当前星期课程数量。
这个项目的核心不是简单写一个静态课程表,而是通过状态变量维护课程数据。用户每添加或删除一门课程,课程列表和统计卡片都会同步变化。这个过程可以很好地体现 ArkUI 的声明式开发思想。
一、项目目标
本次实践主要实现以下目标:
- 创建 HarmonyOS ArkTS 页面;
- 使用
@Entry和@Component定义页面组件; - 使用
@State管理页面状态; - 使用
TextInput接收课程名称、教师、地点和时间; - 使用
Button实现星期切换、类型选择、添加课程和删除课程; - 使用数组保存课程记录;
- 使用
List和ForEach渲染课程列表; - 支持按星期筛选课程;
- 支持课程类型选择;
- 根据课程数组动态统计课程数量;
- 支持删除单条课程记录;
- 支持清空当前星期课程;
- 使用空状态提示优化无课程页面;
- 使用
@Builder封装统计卡片、星期按钮、类型按钮和课程卡片; - 完成一个可以运行的校园课程表页面。
这个项目虽然是单页面应用,但功能链路比较完整,适合作为 ArkTS 页面开发的综合练习。
二、技术栈
| 类型 | 内容 |
|---|---|
| 开发方向 | HarmonyOS 应用开发 |
| 开发语言 | ArkTS |
| UI 框架 | ArkUI |
| SDK 版本 | HarmonyOS API 23 及以上 |
| 工程模型 | Stage 模型 |
| 核心组件 | Text / TextInput / Button / Column / Row / List / ForEach |
| 状态管理 | @State |
| 数据处理 | 数组遍历 / filter / 条件判断 |
| 项目入口 | entry/src/main/ets/pages/Index.ets |
| 运行平台 | 模拟器或真机 |
本项目是 HarmonyOS 原生 ArkTS 项目。页面主体由 ArkUI 组件构建,核心逻辑写在 Index.ets 文件中,不依赖后端接口,也不需要额外配置数据库。
三、为什么选择校园课程表项目
校园课程表应用适合作为 ArkTS 练习项目,主要有以下几个原因。
第一,业务场景真实。课程表是学生日常学习中经常使用的工具,项目功能容易理解,也方便运行测试。
第二,交互流程完整。用户需要输入课程信息、选择星期、选择课程类型、添加课程、查看课程列表、切换星期和删除课程。这个流程比普通静态页面更接近真实应用。
第三,适合练习数组操作。每一门课程都是数组中的一个对象。添加课程就是向数组插入数据,删除课程就是通过编号过滤数组,筛选课程就是根据星期过滤数组。
第四,适合理解状态管理。课程名称、教师、地点、时间、当前星期、当前课程类型和课程列表都属于页面状态。状态变化后,页面会自动更新。
第五,扩展空间比较大。基础课程表完成后,还可以继续增加本地存储、课程提醒、单双周设置、课程颜色、节次管理和课程详情页等功能。
在本项目中,courses 是最核心的数据源。页面中的课程列表、课程数量统计和当前星期课程展示都由它计算或渲染得到。这样可以避免多个数据来源不一致的问题。
四、功能规则说明
本文实现的校园课程表主要包含以下课程信息:
| 字段 | 含义 |
|---|---|
| 课程名称 | 例如数据库原理、Java 程序设计 |
| 任课教师 | 课程对应的教师姓名 |
| 上课地点 | 教室或实验室位置 |
| 上课时间 | 例如 08:30-10:00 |
| 星期 | 周一到周日 |
| 类型 | 专业课、公共课、实验课、选修课 |
页面默认显示“周一”的课程。用户可以点击星期按钮切换到不同日期,查看对应课程。
课程统计规则如下:
本周课程数 = 所有课程记录数量
当前星期课程数 = 当前选中星期下的课程数量
如果当前星期没有课程,页面会显示空状态提示,而不是直接留白。
五、项目结构
本项目主要修改首页文件:
entry
└── src
└── main
└── ets
└── pages
└── Index.ets
其中:
| 文件 | 作用 |
|---|---|
| Index.ets | 编写页面结构、状态数据和课程处理逻辑 |
本文不涉及复杂路由,也不需要额外创建多个页面。对于练习项目来说,把主要逻辑集中在一个 Index.ets 文件中更方便理解。
如果后续继续扩展,可以考虑把课程卡片、星期按钮、统计卡片和输入区域拆分成独立组件。
六、核心实现思路
本项目的核心流程如下:
- 定义课程记录数据结构;
- 使用
@State保存课程输入内容、当前星期、当前类型和课程数组; - 用户输入课程名称、教师、地点和时间;
- 用户选择课程类型;
- 用户选择当前星期;
- 点击添加按钮后生成新的课程记录;
- 使用课程数组保存全部课程;
- 根据当前星期筛选课程;
- 使用
ForEach渲染课程列表; - 根据课程数组统计本周课程数量;
- 根据筛选结果统计当前星期课程数量;
- 点击删除按钮后删除指定课程;
- 点击清空按钮后清空当前星期课程;
- 当当前星期没有课程时显示空状态提示。
项目中最重要的状态变量如下:
@State courseName: string = ''
@State teacherName: string = ''
@State placeName: string = ''
@State timeText: string = ''
@State selectedDay: string = '周一'
@State courseType: string = '专业课'
@State courses: CourseItem[] = []
@State nextId: number = 1
其中:
| 状态变量 | 作用 |
|---|---|
| courseName | 保存课程名称输入 |
| teacherName | 保存教师输入 |
| placeName | 保存地点输入 |
| timeText | 保存时间输入 |
| selectedDay | 保存当前选中的星期 |
| courseType | 保存当前课程类型 |
| courses | 保存课程记录数组 |
| nextId | 生成课程唯一编号 |
courses 是本项目中最重要的数据。课程列表和统计数据都依赖这个数组。
七、Index.ets 完整代码
打开文件:
entry/src/main/ets/pages/Index.ets
将其中内容替换为下面代码:
interface CourseItem {
id: number
name: string
teacher: string
place: string
time: string
day: string
type: string
}
@Entry
@Component
struct Index {
@State courseName: string = ''
@State teacherName: string = ''
@State placeName: string = ''
@State timeText: string = ''
@State selectedDay: string = '周一'
@State courseType: string = '专业课'
@State nextId: number = 5
@State courses: CourseItem[] = [
{
id: 1,
name: '数据库原理',
teacher: '王老师',
place: '教学楼 A203',
time: '08:30-10:00',
day: '周一',
type: '专业课'
},
{
id: 2,
name: 'Java 程序设计',
teacher: '李老师',
place: '实验楼 B401',
time: '10:20-11:50',
day: '周一',
type: '实验课'
},
{
id: 3,
name: '大学英语',
teacher: '陈老师',
place: '教学楼 C105',
time: '14:00-15:30',
day: '周三',
type: '公共课'
},
{
id: 4,
name: '创新创业基础',
teacher: '赵老师',
place: '综合楼 D201',
time: '15:50-17:20',
day: '周五',
type: '选修课'
}
]
private addCourse(): void {
let name: string = this.courseName.trim()
let teacher: string = this.teacherName.trim()
let place: string = this.placeName.trim()
let time: string = this.timeText.trim()
if (name.length === 0 || teacher.length === 0 || place.length === 0 || time.length === 0) {
return
}
let course: CourseItem = {
id: this.nextId,
name: name,
teacher: teacher,
place: place,
time: time,
day: this.selectedDay,
type: this.courseType
}
this.courses = [course, ...this.courses]
this.nextId++
this.courseName = ''
this.teacherName = ''
this.placeName = ''
this.timeText = ''
}
private deleteCourse(id: number): void {
this.courses = this.courses.filter((item: CourseItem) => item.id !== id)
}
private clearCurrentDay(): void {
this.courses = this.courses.filter((item: CourseItem) => item.day !== this.selectedDay)
}
private getCurrentDayCourses(): CourseItem[] {
return this.courses.filter((item: CourseItem) => item.day === this.selectedDay)
}
private getTypeCount(type: string): number {
return this.courses.filter((item: CourseItem) => item.type === type).length
}
private getTypeColor(type: string): string {
if (type === '专业课') {
return '#0A59F7'
}
if (type === '实验课') {
return '#10B981'
}
if (type === '公共课') {
return '#F59E0B'
}
return '#8B5CF6'
}
@Builder
StatCard(title: string, value: string, color: string) {
Column() {
Text(value)
.fontSize(22)
.fontWeight(FontWeight.Bold)
.fontColor(color)
Text(title)
.fontSize(13)
.fontColor('#6B7280')
.margin({ top: 4 })
}
.width('31%')
.height(78)
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.White)
.borderRadius(16)
.shadow({
radius: 10,
color: '#12000000',
offsetX: 0,
offsetY: 4
})
}
@Builder
DayButton(text: string) {
Button(text)
.height(34)
.fontSize(13)
.fontColor(this.selectedDay === text ? Color.White : '#4B5563')
.backgroundColor(this.selectedDay === text ? '#0A59F7' : '#EEF2F8')
.borderRadius(17)
.onClick(() => {
this.selectedDay = text
})
}
@Builder
TypeButton(text: string) {
Button(text)
.height(34)
.fontSize(13)
.fontColor(this.courseType === text ? Color.White : '#4B5563')
.backgroundColor(this.courseType === text ? this.getTypeColor(text) : '#EEF2F8')
.borderRadius(17)
.onClick(() => {
this.courseType = text
})
}
@Builder
CourseCard(item: CourseItem) {
Column() {
Row() {
Column() {
Text(item.name)
.fontSize(17)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
Text(`${item.day} ${item.time}`)
.fontSize(13)
.fontColor('#6B7280')
.margin({ top: 6 })
Text(`${item.teacher} · ${item.place}`)
.fontSize(13)
.fontColor('#9CA3AF')
.margin({ top: 6 })
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1)
Text(item.type)
.fontSize(12)
.fontColor(Color.White)
.backgroundColor(this.getTypeColor(item.type))
.borderRadius(12)
.padding({ left: 10, right: 10, top: 5, bottom: 5 })
}
.width('100%')
Button('删除课程')
.height(32)
.fontSize(13)
.fontColor('#EF4444')
.backgroundColor('#FEF2F2')
.borderRadius(14)
.margin({ top: 12 })
.alignSelf(ItemAlign.End)
.onClick(() => {
this.deleteCourse(item.id)
})
}
.width('100%')
.padding(14)
.margin({ bottom: 12 })
.backgroundColor(Color.White)
.borderRadius(16)
.shadow({
radius: 10,
color: '#12000000',
offsetX: 0,
offsetY: 3
})
}
build() {
Column() {
Text('校园课程表')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
.margin({ top: 22 })
Text('基于 HarmonyOS ArkTS 的轻量级课程管理工具')
.fontSize(14)
.fontColor('#6B7280')
.margin({ top: 8, bottom: 22 })
Row() {
this.StatCard('本周课程', `${this.courses.length}`, '#0A59F7')
this.StatCard('当天课程', `${this.getCurrentDayCourses().length}`, '#10B981')
this.StatCard('实验课', `${this.getTypeCount('实验课')}`, '#F59E0B')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Column() {
Text('新增课程')
.fontSize(17)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
.width('100%')
.margin({ bottom: 14 })
TextInput({
placeholder: '请输入课程名称,例如 数据库原理',
text: this.courseName
})
.height(42)
.fontSize(14)
.backgroundColor('#F5F7FA')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.onChange((value: string) => {
this.courseName = value
})
TextInput({
placeholder: '请输入任课教师,例如 王老师',
text: this.teacherName
})
.height(42)
.fontSize(14)
.backgroundColor('#F5F7FA')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.margin({ top: 10 })
.onChange((value: string) => {
this.teacherName = value
})
TextInput({
placeholder: '请输入上课地点,例如 教学楼 A203',
text: this.placeName
})
.height(42)
.fontSize(14)
.backgroundColor('#F5F7FA')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.margin({ top: 10 })
.onChange((value: string) => {
this.placeName = value
})
TextInput({
placeholder: '请输入上课时间,例如 08:30-10:00',
text: this.timeText
})
.height(42)
.fontSize(14)
.backgroundColor('#F5F7FA')
.borderRadius(12)
.padding({ left: 12, right: 12 })
.margin({ top: 10 })
.onChange((value: string) => {
this.timeText = value
})
Text('选择课程类型')
.fontSize(14)
.fontColor('#6B7280')
.width('100%')
.margin({ top: 14, bottom: 10 })
Row() {
this.TypeButton('专业课')
this.TypeButton('公共课')
this.TypeButton('实验课')
this.TypeButton('选修课')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Button(`添加到${this.selectedDay}`)
.height(44)
.fontSize(16)
.fontColor(Color.White)
.backgroundColor('#0A59F7')
.borderRadius(14)
.width('100%')
.margin({ top: 16 })
.onClick(() => {
this.addCourse()
})
}
.width('100%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(18)
.margin({ top: 18 })
.shadow({
radius: 10,
color: '#12000000',
offsetX: 0,
offsetY: 4
})
Text('星期筛选')
.fontSize(17)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
.width('100%')
.margin({ top: 20, bottom: 12 })
Row() {
this.DayButton('周一')
this.DayButton('周二')
this.DayButton('周三')
this.DayButton('周四')
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
Row() {
this.DayButton('周五')
this.DayButton('周六')
this.DayButton('周日')
}
.width('100%')
.justifyContent(FlexAlign.Start)
.margin({ top: 10 })
Row() {
Text(`${this.selectedDay}课程`)
.fontSize(17)
.fontWeight(FontWeight.Bold)
.fontColor('#182431')
Blank()
Button('清空当天')
.height(32)
.fontSize(13)
.fontColor('#EF4444')
.backgroundColor('#FEF2F2')
.borderRadius(14)
.onClick(() => {
this.clearCurrentDay()
})
}
.width('100%')
.margin({ top: 20, bottom: 12 })
if (this.getCurrentDayCourses().length === 0) {
Column() {
Text('当天暂无课程')
.fontSize(16)
.fontColor('#6B7280')
Text('可以在上方输入课程信息,并添加到当前星期。')
.fontSize(13)
.fontColor('#9CA3AF')
.margin({ top: 8 })
}
.width('100%')
.padding(24)
.backgroundColor(Color.White)
.borderRadius(16)
} else {
List() {
ForEach(this.getCurrentDayCourses(), (item: CourseItem) => {
ListItem() {
this.CourseCard(item)
}
}, (item: CourseItem) => item.id.toString())
}
.width('100%')
.layoutWeight(1)
.scrollBar(BarState.Off)
}
}
.width('100%')
.height('100%')
.padding({ left: 18, right: 18 })
.backgroundColor('#F5F7FA')
}
}
八、代码实现说明
1. 定义课程数据结构
项目中使用 CourseItem 接口描述每一条课程记录:
interface CourseItem {
id: number
name: string
teacher: string
place: string
time: string
day: string
type: string
}
字段说明如下:
| 字段 | 作用 |
|---|---|
| id | 课程唯一编号 |
| name | 课程名称 |
| teacher | 任课教师 |
| place | 上课地点 |
| time | 上课时间 |
| day | 上课星期 |
| type | 课程类型 |
其中 id 用来区分不同课程,day 用来按照星期筛选课程,type 用来展示课程类别。
2. 使用 @State 管理页面数据
本项目中使用多个状态变量:
@State courseName: string = ''
@State teacherName: string = ''
@State placeName: string = ''
@State timeText: string = ''
@State selectedDay: string = '周一'
@State courseType: string = '专业课'
@State courses: CourseItem[] = []
这些状态变量分别保存输入内容、当前星期、当前课程类型和课程数组。
当用户输入课程信息、切换星期、选择类型、添加课程或删除课程时,状态数据都会发生变化。ArkUI 会根据最新状态自动刷新页面。
3. 添加课程功能
添加课程通过 addCourse 方法实现:
private addCourse(): void {
let name: string = this.courseName.trim()
let teacher: string = this.teacherName.trim()
let place: string = this.placeName.trim()
let time: string = this.timeText.trim()
if (name.length === 0 || teacher.length === 0 || place.length === 0 || time.length === 0) {
return
}
let course: CourseItem = {
id: this.nextId,
name: name,
teacher: teacher,
place: place,
time: time,
day: this.selectedDay,
type: this.courseType
}
this.courses = [course, ...this.courses]
this.nextId++
}
这里先读取输入框内容,并使用 trim() 去掉前后空格。如果任意输入项为空,就不添加课程。
新增课程会保存当前选中的星期和课程类型,然后插入到课程数组最前面。
4. 按星期筛选课程
当前星期课程通过 getCurrentDayCourses 方法获取:
private getCurrentDayCourses(): CourseItem[] {
return this.courses.filter((item: CourseItem) => item.day === this.selectedDay)
}
这段代码会从全部课程中筛选出 day 等于当前选中星期的课程。
点击不同星期按钮后,selectedDay 会发生变化,页面列表也会显示对应星期的课程。
5. 删除课程功能
删除课程通过 deleteCourse 方法实现:
private deleteCourse(id: number): void {
this.courses = this.courses.filter((item: CourseItem) => item.id !== id)
}
这里使用 id 删除课程,而不是使用课程名称。因为不同星期可能有同名课程,使用唯一编号更安全。
删除后,课程列表和统计数据都会同步更新。
6. 清空当天课程
清空当前星期课程通过 clearCurrentDay 方法实现:
private clearCurrentDay(): void {
this.courses = this.courses.filter((item: CourseItem) => item.day !== this.selectedDay)
}
这段代码会保留所有不是当前星期的课程,从而删除当前星期下的全部课程。
这个功能适合在需要重新整理某一天课程时使用。
7. 课程类型颜色
项目中通过 getTypeColor 方法给不同课程类型设置不同颜色:
private getTypeColor(type: string): string {
if (type === '专业课') {
return '#0A59F7'
}
if (type === '实验课') {
return '#10B981'
}
if (type === '公共课') {
return '#F59E0B'
}
return '#8B5CF6'
}
这样课程卡片中的类型标签会更加直观。用户可以快速区分专业课、实验课、公共课和选修课。
8. 课程统计功能
本项目顶部有三个统计卡片:
| 统计项 | 含义 |
|---|---|
| 本周课程 | 所有课程数量 |
| 当天课程 | 当前星期课程数量 |
| 实验课 | 实验课数量 |
其中,本周课程数量直接使用:
this.courses.length
当天课程数量使用:
this.getCurrentDayCourses().length
实验课数量使用:
this.getTypeCount('实验课')
当课程被添加、删除或清空后,统计数据会自动变化。
9. 空状态提示
当当前星期没有课程时,页面会显示空状态提示:
if (this.getCurrentDayCourses().length === 0) {
Column() {
Text('当天暂无课程')
Text('可以在上方输入课程信息,并添加到当前星期。')
}
}
这样可以避免页面空白,让用户知道当前星期没有课程,并提示下一步操作。
10. 使用 @Builder 封装页面结构
本项目中使用 @Builder 封装了多个页面片段:
@Builder
StatCard(title: string, value: string, color: string)
用于构建统计卡片。
@Builder
DayButton(text: string)
用于构建星期切换按钮。
@Builder
TypeButton(text: string)
用于构建课程类型按钮。
@Builder
CourseCard(item: CourseItem)
用于构建课程卡片。
这样可以减少 build() 方法中的代码堆叠,让页面结构更加清晰,也方便后续维护。
九、运行项目
代码编写完成后,在 DevEco Studio 中选择模拟器或真机运行项目。
运行成功后,页面会显示“校园课程表”。用户可以输入课程名称、任课教师、地点和时间,选择课程类型后,将课程添加到当前星期。
可以按照以下步骤进行测试:
- 打开应用,检查页面是否正常显示;
- 查看默认课程是否正常加载;
- 查看本周课程数量是否正确;
- 点击周一,检查是否显示周一课程;
- 点击周三,检查是否显示周三课程;
- 输入课程名称,例如 操作系统;
- 输入教师,例如 张老师;
- 输入地点,例如 教学楼 B305;
- 输入时间,例如 10:20-11:50;
- 选择课程类型,例如 专业课;
- 点击添加按钮,检查课程是否新增成功;
- 删除某一条课程,检查列表是否更新;
- 点击清空当天,检查当前星期课程是否清空;
- 当前星期没有课程时,检查空状态提示是否显示。
测试结果如下:
| 测试功能 | 测试结果 |
|---|---|
| 页面正常显示 | 成功 |
| 默认课程加载 | 成功 |
| 星期切换 | 成功 |
| 添加课程 | 成功 |
| 删除课程 | 成功 |
| 清空当天课程 | 成功 |
| 本周课程统计 | 成功 |
| 当天课程统计 | 成功 |
| 课程类型展示 | 成功 |
| 空状态提示 | 成功 |
经过测试,应用主要功能可以正常运行,页面状态也能根据用户操作及时刷新。
十、开发中遇到的问题
1. 输入内容需要校验
如果课程名称、教师、地点或时间为空,就不应该添加课程。否则课程卡片中会出现空白内容。
因此添加前需要判断:
if (name.length === 0 || teacher.length === 0 || place.length === 0 || time.length === 0) {
return
}
这样可以避免无效课程进入列表。
2. 星期筛选不能破坏原始数组
切换星期时,不能直接修改原始 courses 数组。否则切换回其他星期时,课程可能已经丢失。
因此项目中使用 getCurrentDayCourses() 返回筛选结果,而不是直接改变 courses 本身。
3. 删除课程需要使用唯一编号
如果使用课程名称删除课程,遇到同名课程时可能会误删。因此项目中使用 id 作为唯一编号。
item.id !== id
这样可以准确删除当前点击的那一门课程。
4. 清空当天课程不能影响其他星期
清空当前星期课程时,只应该删除当前选中星期的数据,其他星期课程应该保留。
因此项目中使用:
item.day !== this.selectedDay
这样可以只过滤掉当前星期的课程。
5. 空课程状态需要提示
如果当前星期没有课程,页面不应该直接显示空白。本项目通过空状态提示告诉用户当前没有课程,并提示可以添加课程。
这样页面在无数据状态下也能保持完整。
十一、总结
本文基于 HarmonyOS 和 ArkTS 实现了一个校园课程表应用。项目通过 @State 管理页面数据,使用 ArkUI 组件完成页面布局,并实现了课程添加、星期筛选、课程类型选择、课程统计、课程删除、清空当天课程和空状态提示等功能。
通过本次实践,主要完成了以下内容:
- 使用
@Entry和@Component创建页面组件; - 使用
@State保存输入内容、当前星期、课程类型和课程数据; - 使用
TextInput获取课程名称、教师、地点和时间; - 使用
Button实现星期切换、类型选择、添加和删除操作; - 使用
List和ForEach渲染课程列表; - 使用
filter()筛选当前星期课程; - 使用
filter()删除指定课程; - 使用条件渲染显示空状态;
- 使用
@Builder封装页面局部结构; - 完成一个可以运行的 HarmonyOS 校园学习工具页面。
这个项目虽然是一个单页面练习,但完整展示了 ArkTS 页面开发中的输入处理、数据记录、状态更新、列表渲染、动态统计和条件展示流程。
后续可以在这个基础上继续扩展,例如:
- 增加本地数据持久化;
- 增加课程详情页;
- 增加课程编辑功能;
- 增加单双周课程;
- 增加上课提醒;
- 增加课程颜色自定义;
- 增加节次选择;
- 增加按课程类型筛选;
- 增加课程搜索功能;
- 增加深色模式适配。
整体来看,校园课程表应用非常适合作为 HarmonyOS ArkTS 的练习项目。它功能清晰、代码量适中、运行效果直观,能够帮助初学者理解 ArkUI 声明式开发和 @State 状态驱动页面刷新的基本思想。
更多推荐



所有评论(0)