HarmonyOS4+NEXT星河版入门与项目实战(19)------状态管理 @Prop@Link@Provide@Consume
本节主要介绍了 @Prop@Link@Provide@Consume 四种装饰器的使用效果以及使用场景。用实际的案例改造实现不同装饰器的效果。
文章目录
1、@Prop@Link@Provide@Consume装饰器图解
这里我们用一张完整的图来汇整@Prop@Link 的作用,如下所示:

这里我们还需要注意的时传递数据的限制。整理如下图:
注意
@Link 传参是地址引用,所以参数前面用 $修饰,不是 this 修饰。
@Provide@Consume 成对使用,@Provide负组件使用,@Consume子组件使用,不需要显示传参。
技巧总结
- 什么时候用@prop : 子组件对父组件传递的数据无更改时
- 什么时候用@Link : 子组件对父组件传递的数据有更改时
2、案例演示
1、模块划分
上节内容,我们讲解了一个任务统计的功能实现,对任务统计功能进行模块划分其实就分成两个部分,上部分,任务统计模块,下部分,任务列表模块,如下所示:

2、模块封装
划分好了对应的模块,我们就可以对相应的模块进行代码封装。这里分成 任务统计模块和列表管理模块
1、任务统计模块
代码如下所示:
@Component
struct TaskStatistics {
//任务总数
@Prop totalTask: number
//任务完成数
@Prop finishTask: number
build() {
//1、任务进度卡片
Row() {
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//重叠容器
Stack() {
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
Row() {
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.totalTask.toString())
.fontSize(24)
}
}
}
.cardBackground()
.margin({ top: 20, bottom: 10 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
2、列表管理模块
代码如下所示:
@Component
struct CreateTaskList {
//任务总数
@Link totalTask: number
//任务完成数
@Link finishTask: number
//任务列表
@State taskList: Task[] = []
CalculateTask() {
//1、更新任务总数量
this.totalTask = this.taskList.length
//2、更新已完成的任务数量
this.finishTask = this.taskList.filter(item => item.finished).length
}
build() {
Column() {
//2、新增任务按钮
Button('新增任务')
.width(200)
.onClick(() => {
//1、新增任务数据
this.taskList.push(new Task())
//2、更新任务总数量
this.CalculateTask()
})
//3、任务列表显示
List({ space: 10 }) {
ForEach(
this.taskList,
(item: Task, id) => {
ListItem() {
Row() {
if (item.finished) {
Text(item.name)
.fontSize(20)
.finishedTaskStyle()
} else {
Text(item.name)
.fontSize(20)
}
Checkbox()
.select(item.finished)
.onChange(val => {
//1、更改任务状态
item.finished = val
//2、任务完成数量变更
this.CalculateTask()
})
}
.cardBackground()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({ end: this.DeleteButton(id) })
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.task_delete'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.taskList.splice(index, 1)
this.CalculateTask()
})
}
}
3、主界面
主界面引用子组件代码如下:
@Entry
@Component
struct TaskPage {
//任务总数
@State totalTask: number = 0
//任务完成数
@State finishTask: number = 0
build() {
Column({ space: 10 }) {
//1、任务统计
TaskStatistics({ finishTask: this.finishTask, totalTask: this.totalTask })
//2、任务李彪
CreateTaskList({ finishTask: $finishTask, totalTask: $totalTask })
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
}
是不是发现页面一下子简洁了,这就是封装带来的效果,简化代码结构,提高代码可读性。
4、完整代码
class Task {
//静态任务Id,静态变量方便任务名称编号获取,且为所有内部属性共享的一个变量
static id: number = 1
//任务名称
name: string = '任务' + Task.id++
//任务完成状态
finished: boolean = false
}
//样式构件 任务卡片样式
@Styles function cardBackground() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 0, color: '#1F000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式 字体灰色,字体中划线删除效果
@Extend(Text) function finishedTaskStyle() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
@Entry
@Component
struct TaskPage {
//任务总数
@State totalTask: number = 0
//任务完成数
@State finishTask: number = 0
build() {
Column({ space: 10 }) {
//1、任务统计
TaskStatistics({ finishTask: this.finishTask, totalTask: this.totalTask })
//2、任务李彪
CreateTaskList({ finishTask: $finishTask, totalTask: $totalTask })
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
}
@Component
struct TaskStatistics {
//任务总数
@Prop totalTask: number
//任务完成数
@Prop finishTask: number
build() {
//1、任务进度卡片
Row() {
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//重叠容器
Stack() {
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
Row() {
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.totalTask.toString())
.fontSize(24)
}
}
}
.cardBackground()
.margin({ top: 20, bottom: 10 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct CreateTaskList {
//任务总数
@Link totalTask: number
//任务完成数
@Link finishTask: number
//任务列表
@State taskList: Task[] = []
CalculateTask() {
//1、更新任务总数量
this.totalTask = this.taskList.length
//2、更新已完成的任务数量
this.finishTask = this.taskList.filter(item => item.finished).length
}
build() {
Column() {
//2、新增任务按钮
Button('新增任务')
.width(200)
.onClick(() => {
//1、新增任务数据
this.taskList.push(new Task())
//2、更新任务总数量
this.CalculateTask()
})
//3、任务列表显示
List({ space: 10 }) {
ForEach(
this.taskList,
(item: Task, id) => {
ListItem() {
Row() {
if (item.finished) {
Text(item.name)
.fontSize(20)
.finishedTaskStyle()
} else {
Text(item.name)
.fontSize(20)
}
Checkbox()
.select(item.finished)
.onChange(val => {
//1、更改任务状态
item.finished = val
//2、任务完成数量变更
this.CalculateTask()
})
}
.cardBackground()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({ end: this.DeleteButton(id) })
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.task_delete'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.taskList.splice(index, 1)
this.CalculateTask()
})
}
}
3、父组件是对象@Prop可以是对象属性
1、案例改造
这里我们可以拿上面任务案例进行改造,上面任务统计在父组件中是两个变量,我们把它改造成一个对象,我们用 TaskInfo 类来定义,代码如下:
class TaskInfo{
//任务总数
totalTask: number = 0
//任务完成数
finishTask: number = 0
}
任务统计模块只是数据的显示,所以在组件内部基本无改动,只是在父组件的调用方式有所变化,如下所示:
//1、任务统计
TaskStatistics({ finishTask: this.taskInfo.finishTask, totalTask: this.taskInfo.totalTask })
列表管理模块涉及到信息变化,所以改动较多
- 变量定义 ---------修改 变更为对象定义 @Link taskInfo: TaskInfo
- 任务计算 --------- this.totalTask 变更为 this.taskInfo.totalTask;this.totalTask 变更为 this.taskInfo.totalTask
- 界面引用传参----------- 变成对象传递CreateTaskList({ taskInfo: $taskInfo })
//任务总数
@Link taskInfo: TaskInfo
CalculateTask() {
//1、更新任务总数量
this.taskInfo.totalTask = this.taskList.length
//2、更新已完成的任务数量
this.taskInfo.totalTask = this.taskList.filter(item => item.finished).length
}
2、完整代码
class Task {
//静态任务Id,静态变量方便任务名称编号获取,且为所有内部属性共享的一个变量
static id: number = 1
//任务名称
name: string = '任务' + Task.id++
//任务完成状态
finished: boolean = false
}
//样式构件 任务卡片样式
@Styles function cardBackground() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 0, color: '#1F000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式 字体灰色,字体中划线删除效果
@Extend(Text) function finishedTaskStyle() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
class TaskInfo{
//任务总数
totalTask: number = 0
//任务完成数
finishTask: number = 0
}
@Entry
@Component
struct TaskPage {
@State taskInfo:TaskInfo = new TaskInfo()
build() {
Column({ space: 10 }) {
//1、任务统计
TaskStatistics({ finishTask: this.taskInfo.finishTask, totalTask: this.taskInfo.totalTask })
//2、任务列表
CreateTaskList({ taskInfo: $taskInfo })
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
}
@Component
struct TaskStatistics {
//任务总数
@Prop totalTask: number
//任务完成数
@Prop finishTask: number
build() {
//1、任务进度卡片
Row() {
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//重叠容器
Stack() {
Progress({
value: this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
Row() {
Text(this.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.totalTask.toString())
.fontSize(24)
}
}
}
.cardBackground()
.margin({ top: 20, bottom: 10 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct CreateTaskList {
//任务总数
@Link taskInfo: TaskInfo
//任务列表
@State taskList: Task[] = []
CalculateTask() {
//1、更新任务总数量
this.taskInfo.totalTask = this.taskList.length
//2、更新已完成的任务数量
this.taskInfo.finishTask = this.taskList.filter(item => item.finished).length
}
build() {
Column() {
//2、新增任务按钮
Button('新增任务')
.width(200)
.onClick(() => {
//1、新增任务数据
this.taskList.push(new Task())
//2、更新任务总数量
this.CalculateTask()
})
//3、任务列表显示
List({ space: 10 }) {
ForEach(
this.taskList,
(item: Task, id) => {
ListItem() {
Row() {
if (item.finished) {
Text(item.name)
.fontSize(20)
.finishedTaskStyle()
} else {
Text(item.name)
.fontSize(20)
}
Checkbox()
.select(item.finished)
.onChange(val => {
//1、更改任务状态
item.finished = val
//2、任务完成数量变更
this.CalculateTask()
})
}
.cardBackground()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({ end: this.DeleteButton(id) })
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.task_delete'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.taskList.splice(index, 1)
this.CalculateTask()
})
}
}
4、@Provide@Consume案例
1、案例改造
我们继续对上面任务统计功能进行改造,用来演示 @Provide@Consume。
我们把主页面 TaskPage 中的
@State taskInfo:TaskInfo = new TaskInfo()
修改为
@Provide taskInfo:TaskInfo = new TaskInfo()
把子组件 CreateTaskList 中的
//任务总数
@Link taskInfo: TaskInfo
修改为
//任务总数
@Consume taskInfo: TaskInfo
子组件 TaskStatistics 修改如下
- 变量定义修改为对象 @Consume taskInfo: TaskInfo
- 数据操作从对象中获取数据 value: this.taskInfo.finishTask
@Component
struct TaskStatistics {
//任务总数
@Consume taskInfo: TaskInfo
build() {
//1、任务进度卡片
Row() {
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//重叠容器
Stack() {
Progress({
value: this.taskInfo.finishTask,
total: this.taskInfo.totalTask,
type: ProgressType.Ring
})
Row() {
Text(this.taskInfo.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.taskInfo.totalTask.toString())
.fontSize(24)
}
}
}
.cardBackground()
.margin({ top: 20, bottom: 10 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
主界面改造,没有了参数传递

2、完整代码
class Task {
//静态任务Id,静态变量方便任务名称编号获取,且为所有内部属性共享的一个变量
static id: number = 1
//任务名称
name: string = '任务' + Task.id++
//任务完成状态
finished: boolean = false
}
//样式构件 任务卡片样式
@Styles function cardBackground() {
.width('95%')
.padding(20)
.backgroundColor(Color.White)
.borderRadius(15)
.shadow({ radius: 0, color: '#1F000000', offsetX: 2, offsetY: 4 })
}
//任务完成样式 字体灰色,字体中划线删除效果
@Extend(Text) function finishedTaskStyle() {
.decoration({ type: TextDecorationType.LineThrough })
.fontColor('#B1B2B1')
}
class TaskInfo{
//任务总数
totalTask: number = 0
//任务完成数
finishTask: number = 0
}
@Entry
@Component
struct TaskPage {
@Provide taskInfo:TaskInfo = new TaskInfo()
build() {
Column({ space: 10 }) {
//1、任务统计
TaskStatistics()
//2、任务列表
CreateTaskList()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F2F3')
}
}
@Component
struct TaskStatistics {
//任务总数
@Consume taskInfo: TaskInfo
build() {
//1、任务进度卡片
Row() {
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
//重叠容器
Stack() {
Progress({
value: this.taskInfo.finishTask,
total: this.taskInfo.totalTask,
type: ProgressType.Ring
})
Row() {
Text(this.taskInfo.finishTask.toString())
.fontSize(24)
.fontColor('#36D')
Text(' / ' + this.taskInfo.totalTask.toString())
.fontSize(24)
}
}
}
.cardBackground()
.margin({ top: 20, bottom: 10 })
.justifyContent(FlexAlign.SpaceEvenly)
}
}
@Component
struct CreateTaskList {
//任务总数
@Consume taskInfo: TaskInfo
//任务列表
@State taskList: Task[] = []
CalculateTask() {
//1、更新任务总数量
this.taskInfo.totalTask = this.taskList.length
//2、更新已完成的任务数量
this.taskInfo.finishTask = this.taskList.filter(item => item.finished).length
}
build() {
Column() {
//2、新增任务按钮
Button('新增任务')
.width(200)
.onClick(() => {
//1、新增任务数据
this.taskList.push(new Task())
//2、更新任务总数量
this.CalculateTask()
})
//3、任务列表显示
List({ space: 10 }) {
ForEach(
this.taskList,
(item: Task, id) => {
ListItem() {
Row() {
if (item.finished) {
Text(item.name)
.fontSize(20)
.finishedTaskStyle()
} else {
Text(item.name)
.fontSize(20)
}
Checkbox()
.select(item.finished)
.onChange(val => {
//1、更改任务状态
item.finished = val
//2、任务完成数量变更
this.CalculateTask()
})
}
.cardBackground()
.justifyContent(FlexAlign.SpaceBetween)
}
.swipeAction({ end: this.DeleteButton(id) })
}
)
}
.width('100%')
.layoutWeight(1)
.alignListItem(ListItemAlign.Center)
}
}
@Builder DeleteButton(index: number) {
Button() {
Image($r('app.media.task_delete'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
this.taskList.splice(index, 1)
this.CalculateTask()
})
}
}
3、总结
本节主要介绍了 @Prop@Link@Provide@Consume 四种装饰器的使用效果以及使用场景。用实际的案例改造实现不同装饰器的效果。
更多推荐




所有评论(0)