码云仓库地址:https://gitee.com/lin_zixiang/hongmeng-learning.git
在\src\main\ets\pages\TaskManager1.ets该文件下
- 效果图
- 页面入口
页面分为了两部分组件,上部分是任务进度的视图,下部分是新增按钮和任务列表
@Entry
@Component
struct TaskPage {
@State totalTask: number = 0
@State finishTask: number = 0
build() {
Column({ space: 20 }) {
//上半部分任务进度组件
progressView({ totalTask: this.totalTask, finishTask: this.finishTask })
//下半部分新增任务+任务列表组件。
progressList({ totalTask: $totalTask, finishTask: $finishTask })
}
.width('100%')
.height('100%')
.padding({ top: 20 })
.backgroundColor('#ffeceaea')
}
}
- 任务进度组件
@Component
struct progressView {
@Prop totalTask: number
@Prop finishTask: number
build() {
Row() {
Text('任务进度:')
.fontWeight(FontWeight.Bold)
.fontSize(30)
//Stack,实现Text叠在进度条的上方
Stack() {
Progress({ value: this.finishTask, type: ProgressType.Ring, total: this.totalTask })
.width(100)
Row() {
Text(this.finishTask + '')
.fontSize(30)
.fontColor('#36D')
Text(' / ' + this.totalTask)
.fontSize(30)
}
}
}
.card()
.justifyContent(FlexAlign.SpaceEvenly)
}
}
- 任务进度列表组件
//任务进度列表组件
@Component
struct progressList {
@Link totalTask: number
@Link finishTask: number
@State task: Task[] = []
build() {
Column({ space: 15 }) {
Button('新增任务')
.width('50%')
.onClick(() => {
this.task.push(new Task()) //id和taskName都是默认值
this.updateTask()
})
//任务列表会超出屏幕,所以用List,可以滑动
List({ space: 10 }) {
ForEach(
this.task,
(item: Task, index) => {
ListItem() {
//提取出任务列表样式,为了实现数组对象可以双向绑定。也就是数组里的对象改变会重新渲染视图
textElemnet({ item: item, onUpdateTask: this.updateTask.bind(this) }) //bind(this),则方法内的this就指向当前组件
}
.swipeAction({ end: this.deleteButton(index) }) //向右滑动时显示构件,并传index用于删除,这个index是数组的下标
}
)
}
.alignListItem(ListItemAlign.Center) //左右居中
.width('100%')
.layoutWeight(1) //List可以往下拖的关键设置,除了前边别的设置的,剩下的都是List的
}
}
//更新已完成和总的数量
updateTask() {
this.totalTask = this.task.length //点击新增,总长度需要随着数组长度改变
this.finishTask = this.task.filter(item => item.isFinish).length //当前完成的值为总的选中的任务,即所有任务先过滤,item.isFinish是返回为true的数据
}
//删除按钮
@Builder deleteButton(index: number) {
Button() {
Image($r('app.media.deleteTask'))
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor('#fff50d0d')
.margin(5)
.onClick(() => {
this.task.splice(index, 1)
this.updateTask()
})
}
}
//因为要使数组中的对象成为双向绑定数据,所以要提取出数据
@Component
struct textElemnet {
@ObjectLink item: Task
onUpdateTask: () => void //变量,类型是函数
build() {
Row() {
if (this.item.isFinish) {
Text(this.item.taskName)
.finishTask()
} else {
Text(this.item.taskName)
}
Checkbox()
.select(this.item.isFinish) //复选款选不选中,取决于isFinish
.onChange((val) => { //val是是否选中的值
this.item.isFinish = val
this.onUpdateTask()
})
}
.justifyContent(FlexAlign.SpaceBetween)
.card()
}
}
- 抽取出来的公共样式或类
//卡片样式
@Styles function card() {
.width('95%')
.backgroundColor('#fff')
.borderRadius(15)
.padding({ top: 20, bottom: 20, left: 20, right: 20 })
}
//任务完成的样式
@Extend(Text) function finishTask() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
//任务的类
@Observed
class Task {
static id: number = 0; //公共的,所有此类对象共享
taskName: string = `任务${++Task.id}` //直接初始化,Task调用
isFinish: boolean = false
}