当前位置:   article > 正文

鸿蒙开发学习笔记——状态管理_鸿蒙状态管理

鸿蒙状态管理

在声明式UI中,是以状态驱动试图更新:

读取状态(State)渲染视图(View),用户在视图中互动,互动事件又更变状态。

状态(State):指驱动视图更新的数据(被装饰器标记的变量,如:@State message)

视图(View):基于UI描述渲染得到的用户界面

一、@State装饰器

1.@State特性

1)@State装饰器标记的变量必须初始化,不能为空值

2)@State支持Object、class、string、number、boolean、enum类型以及这些类型的数组

3)嵌套类型(比如Object中嵌套一个Object)以及数组中的对象属性无法触发试图更新

2.特性例子

1)简单类型如String、number

  1. @Entry
  2. @Component
  3. struct StatePage {
  4. @State name: string = 'Jack'
  5. @State age: number = 21
  6. build() {
  7. Column() {
  8. // 要引用两个文本,使用``,在键盘Esc下面 Tab上面
  9. Text(`${this.name} : ${this.age}`)
  10. .fontSize(50)
  11. .fontWeight(FontWeight.Bold)
  12. .onClick(() => {
  13. this.age++
  14. })
  15. }
  16. .width('100%')
  17. .height('100%')
  18. .justifyContent(FlexAlign.Center)
  19. }
  20. }

此代码实现的界面如下:

点击前:

点击后数字加1。

2)复杂类型,如class

  1. class Person {
  2. name: string
  3. age: number
  4. constructor(name: string, age: number) {
  5. this.name = name
  6. this.age = age
  7. }
  8. }
  9. @Entry
  10. @Component
  11. struct StatePage2 {
  12. @State p: Person = new Person('Jack', 21)
  13. build() {
  14. Column() {
  15. // 要引用两个文本,使用``,在键盘Esc下面 Tab上面
  16. Text(`${this.p.name} : ${this.p.age}`)
  17. .fontSize(50)
  18. .fontWeight(FontWeight.Bold)
  19. .onClick(() => {
  20. this.p.age++
  21. })
  22. }
  23. .width('100%')
  24. .height('100%')
  25. .justifyContent(FlexAlign.Center)
  26. }
  27. }

也可实现上述效果

3)嵌套类型

  1. class Person {
  2. name: string
  3. age: number
  4. gf: Person
  5. constructor(name: string, age: number, gf?: Person) {
  6. this.name = name
  7. this.age = age
  8. this.gf = gf
  9. }
  10. }
  11. @Entry
  12. @Component
  13. struct StatePage2 {
  14. @State p: Person = new Person('Jack', 21, new Person('Rose', 20))
  15. build() {
  16. Column() {
  17. // 要引用两个文本,使用``,在键盘Esc下面 Tab上面
  18. Text(`${this.p.name} : ${this.p.age}`)
  19. .fontSize(50)
  20. .fontWeight(FontWeight.Bold)
  21. .onClick(() => {
  22. this.p.age++
  23. })
  24. Text(`${this.p.gf.name} : ${this.p.gf.age}`)
  25. .fontSize(50)
  26. .fontWeight(FontWeight.Bold)
  27. .onClick(() => {
  28. this.p.gf.age++
  29. })
  30. }
  31. .width('100%')
  32. .height('100%')
  33. .justifyContent(FlexAlign.Center)
  34. }
  35. }

效果图:

只有点击Jack的年龄才有反应,点击Rose的年龄则没有。但是Rose的年龄确实改变了,在点击Jack的年龄后重新渲染页面才显示出来。

4)数组

增、删、重新赋值数组可以触发重新渲染

  1. class Person {
  2. name: string
  3. age: number
  4. gf: Person
  5. constructor(name: string, age: number, gf?: Person) {
  6. this.name = name
  7. this.age = age
  8. this.gf = gf
  9. }
  10. }
  11. @Entry
  12. @Component
  13. struct StatePage2 {
  14. idx: number = 1
  15. @State p: Person = new Person('Jack', 21)
  16. @State friends: Person[] = [
  17. new Person('Mike', 22),
  18. new Person('Tom', 23)
  19. ]
  20. build() {
  21. Column() {
  22. // 要引用两个文本,使用``,在键盘Esc下面 Tab上面
  23. Text(`${this.p.name} : ${this.p.age}`)
  24. .fontSize(50)
  25. .fontWeight(FontWeight.Bold)
  26. .onClick(() => {
  27. this.p.age++
  28. })
  29. Button('add friends')
  30. .onClick(() => {
  31. // push 向数组中添加新元素
  32. this.friends.push(new Person('朋友' + this.idx++, 20))
  33. })
  34. Text('=friends=')
  35. .fontSize(50)
  36. .fontWeight(FontWeight.Bold)
  37. ForEach(
  38. this.friends,
  39. (p, index) => {
  40. Row() {
  41. Text(`${p.name} : ${p.age}`)
  42. .fontSize(30)
  43. .onClick(() => {
  44. // 如果是p.age++,不是修改数组元素,是对象内的属性变更,无法触发重新渲染
  45. this.friends[index] = new Person(p.name, p.age + 1)
  46. })
  47. Button('delete')
  48. .onClick(() => {
  49. // 从当前角标位置开始剔除,剔除1个
  50. this.friends.splice(index, 1)
  51. })
  52. }
  53. .width('100%')
  54. .justifyContent(FlexAlign.SpaceAround)
  55. }
  56. )
  57. }
  58. .width('100%')
  59. .height('100%')
  60. .padding(20)
  61. }
  62. }

效果图:

3.任务管理案例

1)效果图

2)框架

  1. // 任务类 ———— 一般是放在单独的文件中然后导入
  2. class Task {
  3. // 静态变量,类中所有对象共享
  4. static id: number = 1
  5. // 任务名称
  6. name: string = `任务${Task.id++}`
  7. // 任务状态:是否完成
  8. finished: boolean = false
  9. }
  10. // 统一的卡片样式
  11. @Styles function card() {
  12. .width("95%")
  13. .padding(20)
  14. .backgroundColor(Color.White)
  15. .borderRadius(15)
  16. .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
  17. }
  18. // 任务完成样式
  19. @Extend(Text) function finishedTask() {
  20. .decoration({ type: TextDecorationType.LineThrough })
  21. .fontColor('#B1B2B1')
  22. }
  23. @Entry
  24. @Component
  25. struct PropPage {
  26. // 总任务数
  27. @State totalTask: number = 0
  28. //已完成任务数
  29. @State finishTask: number = 0
  30. // 任务数组
  31. @State tasks: Task[] = []
  32. build() {
  33. Column({ space: 10 }) {
  34. // 1.任务进度卡片
  35. // 2.新增任务按钮
  36. // 3.任务列表
  37. }
  38. .width('100%')
  39. .height('100%')
  40. .backgroundColor('#F1F2F3')
  41. }
  42. }

3)任务进度卡片

代码:

  1. // 1.任务进度卡片
  2. Row() {
  3. Text('任务进度')
  4. .fontSize(30)
  5. .fontWeight(FontWeight.Bold)
  6. // Stack 堆叠容器
  7. Stack() {
  8. // 进度条
  9. Progress({
  10. value: this.finishTask,
  11. total: this.totalTask,
  12. type: ProgressType.Ring
  13. })
  14. .width(100)
  15. Row() {
  16. Text(this.finishTask.toString())
  17. .fontSize(24)
  18. .fontColor(Color.Blue)
  19. Text(' / ' + this.totalTask.toString())
  20. .fontSize(24)
  21. }
  22. }
  23. }.card()
  24. .margin({ top: 20, bottom: 10 })
  25. .justifyContent(FlexAlign.SpaceEvenly)

效果图:

 

4)新增任务按钮

  1. // 2.新增任务按钮
  2. Button('新增任务')
  3. .width(200)
  4. .onClick(() => {
  5. // 1)新增任务数据
  6. this.tasks.push(new Task())
  7. // 2)更新任务总数量
  8. this.totalTask = this.tasks.length
  9. })

5)任务列表

  1. // 3.任务列表
  2. ForEach(
  3. this.tasks,
  4. (item: Task, index) => {
  5. Row() {
  6. Text(item.name)
  7. .fontSize(20)
  8. // 多选框工具
  9. Checkbox()
  10. .select(item.finished)
  11. .onChange(val => {
  12. // 1)更新当前任务状态
  13. item.finished = val
  14. // 2)更新已完成任务数量
  15. this.finishTask = this.tasks.filter(item => item.finished).length
  16. })
  17. }
  18. .card()
  19. }
  20. )

6)优化代码

我们将更新抽取出来,写成一个函数

  1. handleTaskChange() {
  2. // 1.更新任务总数量
  3. this.totalTask = this.tasks.length
  4. // 2.更新已完成任务数量
  5. this.finishTask = this.tasks.filter(item => item.finished).length
  6. }

 7)将任务列表写进List容器中

  1. // 3.任务列表
  2. List({ space: 10 }) {
  3. ForEach(
  4. this.tasks,
  5. (item: Task, index) => {
  6. ListItem() {
  7. Row() {
  8. Text(item.name)
  9. .fontSize(20)
  10. // 多选框工具
  11. Checkbox()
  12. .select(item.finished)
  13. .onChange(val => {
  14. // 1)更新当前任务状态
  15. item.finished = val
  16. // 2)更新
  17. this.handleTaskChange()
  18. })
  19. }
  20. .card()
  21. .layoutWeight(1)
  22. .justifyContent(FlexAlign.SpaceBetween)
  23. }
  24. }
  25. )
  26. }
  27. .width('100%')
  28. .alignListItem(ListItemAlign.Center)

8)编写功能左滑删除按钮

在media中添加删除图标

 

创建局部自定义组件删除按钮

  1. @Builder DeleteButton(index: number) {
  2. Button() {
  3. Image($r('app.media.ic_public_list_deleted'))
  4. .fillColor(Color.White)
  5. .width(20)
  6. }
  7. .width(40)
  8. .height(40)
  9. .type(ButtonType.Circle)
  10. .backgroundColor(Color.Red)
  11. .margin(5)
  12. .onClick(() => {
  13. this.tasks.splice(index, 1)
  14. this.handleTaskChange()
  15. })
  16. }

ListItem添加左滑组件

.swipeAction({ end: this.DeleteButton(index) })

9)完整代码

  1. // 任务类 ———— 一般是放在单独的文件中然后导入
  2. class Task {
  3. // 静态变量,类中所有对象共享
  4. static id: number = 1
  5. // 任务名称
  6. name: string = `任务${Task.id++}`
  7. // 任务状态:是否完成
  8. finished: boolean = false
  9. }
  10. // 统一的卡片样式
  11. @Styles function card() {
  12. .width("95%")
  13. .padding(20)
  14. .backgroundColor(Color.White)
  15. .borderRadius(15)
  16. .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
  17. }
  18. // 任务完成样式
  19. @Extend(Text) function finishedTask() {
  20. .decoration({ type: TextDecorationType.LineThrough })
  21. .fontColor('#B1B2B1')
  22. }
  23. @Entry
  24. @Component
  25. struct PropPage {
  26. // 总任务数
  27. @State totalTask: number = 0
  28. //已完成任务数
  29. @State finishTask: number = 0
  30. // 任务数组
  31. @State tasks: Task[] = []
  32. handleTaskChange() {
  33. // 1.更新任务总数量
  34. this.totalTask = this.tasks.length
  35. // 2.更新已完成任务数量
  36. this.finishTask = this.tasks.filter(item => item.finished).length
  37. }
  38. build() {
  39. Column({ space: 10 }) {
  40. // 1.任务进度卡片
  41. Row() {
  42. Text('任务进度')
  43. .fontSize(30)
  44. .fontWeight(FontWeight.Bold)
  45. // Stack 堆叠容器
  46. Stack() {
  47. // 进度条
  48. Progress({
  49. value: this.finishTask,
  50. total: this.totalTask,
  51. type: ProgressType.Ring
  52. })
  53. .width(100)
  54. Row() {
  55. Text(this.finishTask.toString())
  56. .fontSize(24)
  57. .fontColor(Color.Blue)
  58. Text(' / ' + this.totalTask.toString())
  59. .fontSize(24)
  60. }
  61. }
  62. }.card()
  63. .margin({ top: 20, bottom: 10 })
  64. .justifyContent(FlexAlign.SpaceEvenly)
  65. // 2.新增任务按钮
  66. Button('新增任务')
  67. .width(200)
  68. .onClick(() => {
  69. // 1)新增任务数据
  70. this.tasks.push(new Task())
  71. // 2)更新
  72. this.handleTaskChange()
  73. })
  74. // 3.任务列表
  75. List({ space: 10 }) {
  76. ForEach(
  77. this.tasks,
  78. (item: Task, index) => {
  79. ListItem() {
  80. Row() {
  81. Text(item.name)
  82. .fontSize(20)
  83. // 多选框工具
  84. Checkbox()
  85. .select(item.finished)
  86. .onChange(val => {
  87. // 1)更新当前任务状态
  88. item.finished = val
  89. // 2)更新
  90. this.handleTaskChange()
  91. })
  92. }
  93. .card()
  94. .layoutWeight(1)
  95. .justifyContent(FlexAlign.SpaceBetween)
  96. }
  97. .swipeAction({ end: this.DeleteButton(index) })
  98. }
  99. )
  100. }
  101. .width('100%')
  102. .alignListItem(ListItemAlign.Center)
  103. }
  104. .width('100%')
  105. .height('100%')
  106. .backgroundColor('#F1F2F3')
  107. }
  108. @Builder DeleteButton(index: number) {
  109. Button() {
  110. Image($r('app.media.ic_public_list_deleted'))
  111. .fillColor(Color.White)
  112. .width(20)
  113. }
  114. .width(40)
  115. .height(40)
  116. .type(ButtonType.Circle)
  117. .backgroundColor(Color.Red)
  118. .margin(5)
  119. .onClick(() => {
  120. this.tasks.splice(index, 1)
  121. this.handleTaskChange()
  122. })
  123. }
  124. }

效果图:

二、@Prop和@Link

上面的任务管理案例代码可读性较差,我们可以通过构建自定义组件来使代码可读性提高。而当父子组件之间需要数据同步时,可使用@Prop和@Link装饰器

@Prop@Link
同步类型单向同步双向同步
允许装饰的变量类型

1.@Prop只支持string、number、boolean、enum类型

2.父组件对象类型,子组件是对象属性

3.不可以是数组、any

1.父子类型一致:string、number、boolean、enum、object、class,以及他们的数组

2.数组中元素增、删、替换会引起刷新

3.嵌套类型以及数组中的对象属性无法触发试图更新

初始化方式不允许子组件初始化父组件传递,禁止子组件初始化

1.同步类型

事例代码:

  1. // 任务类 ———— 一般是放在单独的文件中然后导入
  2. class Task {
  3. // 静态变量,类中所有对象共享
  4. static id: number = 1
  5. // 任务名称
  6. name: string = `任务${Task.id++}`
  7. // 任务状态:是否完成
  8. finished: boolean = false
  9. }
  10. // 统一的卡片样式
  11. @Styles function card() {
  12. .width("95%")
  13. .padding(20)
  14. .backgroundColor(Color.White)
  15. .borderRadius(15)
  16. .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
  17. }
  18. // 任务完成样式
  19. @Extend(Text) function finishedTask() {
  20. .decoration({ type: TextDecorationType.LineThrough })
  21. .fontColor('#B1B2B1')
  22. }
  23. @Entry
  24. @Component
  25. struct PropPage {
  26. // 总任务数
  27. @State totalTask: number = 0
  28. //已完成任务数
  29. @State finishTask: number = 0
  30. build() {
  31. Column({ space: 10 }) {
  32. // 1.任务进度卡片
  33. TaskStatistics({ finishTask: this.finishTask, totalTask: this.totalTask })
  34. // 2.任务列表
  35. TaskList({ finishTask: $finishTask, totalTask: $totalTask })
  36. }
  37. .width('100%')
  38. .height('100%')
  39. .backgroundColor('#F1F2F3')
  40. }
  41. }
  42. @Component
  43. struct TaskStatistics {
  44. @Prop finishTask: number
  45. @Prop totalTask: number
  46. build() {
  47. // 1.任务进度卡片
  48. Row() {
  49. Text('任务进度')
  50. .fontSize(30)
  51. .fontWeight(FontWeight.Bold)
  52. // Stack 堆叠容器
  53. Stack() {
  54. // 进度条
  55. Progress({
  56. value: this.finishTask,
  57. total: this.totalTask,
  58. type: ProgressType.Ring
  59. })
  60. .width(100)
  61. Row() {
  62. Text(this.finishTask.toString())
  63. .fontSize(24)
  64. .fontColor(Color.Blue)
  65. Text(' / ' + this.totalTask.toString())
  66. .fontSize(24)
  67. }
  68. }
  69. }.card()
  70. .margin({ top: 20, bottom: 10 })
  71. .justifyContent(FlexAlign.SpaceEvenly)
  72. }
  73. }
  74. @Component
  75. struct TaskList {
  76. // 总任务数
  77. @Link totalTask: number
  78. //已完成任务数
  79. @Link finishTask: number
  80. // 任务数组
  81. @State tasks: Task[] = []
  82. handleTaskChange() {
  83. // 1.更新任务总数量
  84. this.totalTask = this.tasks.length
  85. // 2.更新已完成任务数量
  86. this.finishTask = this.tasks.filter(item => item.finished).length
  87. }
  88. build() {
  89. Column() {
  90. // 2.新增任务按钮
  91. Button('新增任务')
  92. .width(200)
  93. .onClick(() => {
  94. // 1)新增任务数据
  95. this.tasks.push(new Task())
  96. // 2)更新
  97. this.handleTaskChange()
  98. })
  99. // 3.任务列表
  100. List({ space: 10 }) {
  101. ForEach(
  102. this.tasks,
  103. (item: Task, index) => {
  104. ListItem() {
  105. Row() {
  106. Text(item.name)
  107. .fontSize(20)
  108. // 多选框工具
  109. Checkbox()
  110. .select(item.finished)
  111. .onChange(val => {
  112. // 1)更新当前任务状态
  113. item.finished = val
  114. // 2)更新
  115. this.handleTaskChange()
  116. })
  117. }
  118. .card()
  119. .layoutWeight(1)
  120. .justifyContent(FlexAlign.SpaceBetween)
  121. }
  122. .swipeAction({ end: this.DeleteButton(index) })
  123. }
  124. )
  125. }
  126. .width('100%')
  127. .alignListItem(ListItemAlign.Center)
  128. }
  129. }
  130. @Builder DeleteButton(index: number) {
  131. Button() {
  132. Image($r('app.media.ic_public_list_deleted'))
  133. .fillColor(Color.White)
  134. .width(20)
  135. }
  136. .width(40)
  137. .height(40)
  138. .type(ButtonType.Circle)
  139. .backgroundColor(Color.Red)
  140. .margin(5)
  141. .onClick(() => {
  142. this.tasks.splice(index, 1)
  143. this.handleTaskChange()
  144. })
  145. }
  146. }

2. 允许装饰的变量类型

将案例再次进行改造

  1. // 任务类 ———— 一般是放在单独的文件中然后导入
  2. class Task {
  3. // 静态变量,类中所有对象共享
  4. static id: number = 1
  5. // 任务名称
  6. name: string = `任务${Task.id++}`
  7. // 任务状态:是否完成
  8. finished: boolean = false
  9. }
  10. // 统一的卡片样式
  11. @Styles function card() {
  12. .width("95%")
  13. .padding(20)
  14. .backgroundColor(Color.White)
  15. .borderRadius(15)
  16. .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
  17. }
  18. // 任务完成样式
  19. @Extend(Text) function finishedTask() {
  20. .decoration({ type: TextDecorationType.LineThrough })
  21. .fontColor('#B1B2B1')
  22. }
  23. class StatInfo {
  24. // 总任务数
  25. totalTask: number = 0
  26. //已完成任务数
  27. finishTask: number = 0
  28. }
  29. @Entry
  30. @Component
  31. struct PropPage {
  32. // 统计信息
  33. @State stat: StatInfo = new StatInfo()
  34. build() {
  35. Column({ space: 10 }) {
  36. // 1.任务进度卡片
  37. TaskStatistics({ finishTask: this.stat.finishTask, totalTask: this.stat.totalTask })
  38. // 2.任务列表
  39. TaskList({ stat: $stat })
  40. }
  41. .width('100%')
  42. .height('100%')
  43. .backgroundColor('#F1F2F3')
  44. }
  45. }
  46. @Component
  47. struct TaskStatistics {
  48. @Prop finishTask: number
  49. @Prop totalTask: number
  50. build() {
  51. // 1.任务进度卡片
  52. Row() {
  53. Text('任务进度')
  54. .fontSize(30)
  55. .fontWeight(FontWeight.Bold)
  56. // Stack 堆叠容器
  57. Stack() {
  58. // 进度条
  59. Progress({
  60. value: this.finishTask,
  61. total: this.totalTask,
  62. type: ProgressType.Ring
  63. })
  64. .width(100)
  65. Row() {
  66. Text(this.finishTask.toString())
  67. .fontSize(24)
  68. .fontColor(Color.Blue)
  69. Text(' / ' + this.totalTask.toString())
  70. .fontSize(24)
  71. }
  72. }
  73. }.card()
  74. .margin({ top: 20, bottom: 10 })
  75. .justifyContent(FlexAlign.SpaceEvenly)
  76. }
  77. }
  78. @Component
  79. struct TaskList {
  80. // 统计信息
  81. @Link stat: StatInfo
  82. // 任务数组
  83. @State tasks: Task[] = []
  84. handleTaskChange() {
  85. // 1.更新任务总数量
  86. this.stat.totalTask = this.tasks.length
  87. // 2.更新已完成任务数量
  88. this.stat.finishTask = this.tasks.filter(item => item.finished).length
  89. }
  90. build() {
  91. Column() {
  92. // 2.新增任务按钮
  93. Button('新增任务')
  94. .width(200)
  95. .onClick(() => {
  96. // 1)新增任务数据
  97. this.tasks.push(new Task())
  98. // 2)更新
  99. this.handleTaskChange()
  100. })
  101. // 3.任务列表
  102. List({ space: 10 }) {
  103. ForEach(
  104. this.tasks,
  105. (item: Task, index) => {
  106. ListItem() {
  107. Row() {
  108. Text(item.name)
  109. .fontSize(20)
  110. // 多选框工具
  111. Checkbox()
  112. .select(item.finished)
  113. .onChange(val => {
  114. // 1)更新当前任务状态
  115. item.finished = val
  116. // 2)更新
  117. this.handleTaskChange()
  118. })
  119. }
  120. .card()
  121. .layoutWeight(1)
  122. .justifyContent(FlexAlign.SpaceBetween)
  123. }
  124. .swipeAction({ end: this.DeleteButton(index) })
  125. }
  126. )
  127. }
  128. .width('100%')
  129. .alignListItem(ListItemAlign.Center)
  130. }
  131. }
  132. @Builder DeleteButton(index: number) {
  133. Button() {
  134. Image($r('app.media.ic_public_list_deleted'))
  135. .fillColor(Color.White)
  136. .width(20)
  137. }
  138. .width(40)
  139. .height(40)
  140. .type(ButtonType.Circle)
  141. .backgroundColor(Color.Red)
  142. .margin(5)
  143. .onClick(() => {
  144. this.tasks.splice(index, 1)
  145. this.handleTaskChange()
  146. })
  147. }
  148. }

三、@Provide和@Consume

@Provide和@Consume可以跨组件提供类似于@State和@Link的双向同步,不需要显示传参,自动传递。刚方便,但是资源损耗大。

案例改造代码:

  1. // 任务类 ———— 一般是放在单独的文件中然后导入
  2. class Task {
  3. // 静态变量,类中所有对象共享
  4. static id: number = 1
  5. // 任务名称
  6. name: string = `任务${Task.id++}`
  7. // 任务状态:是否完成
  8. finished: boolean = false
  9. }
  10. // 统一的卡片样式
  11. @Styles function card() {
  12. .width("95%")
  13. .padding(20)
  14. .backgroundColor(Color.White)
  15. .borderRadius(15)
  16. .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
  17. }
  18. // 任务完成样式
  19. @Extend(Text) function finishedTask() {
  20. .decoration({ type: TextDecorationType.LineThrough })
  21. .fontColor('#B1B2B1')
  22. }
  23. class StatInfo {
  24. // 总任务数
  25. totalTask: number = 0
  26. //已完成任务数
  27. finishTask: number = 0
  28. }
  29. @Entry
  30. @Component
  31. struct PropPage {
  32. // 统计信息
  33. @Provide stat: StatInfo = new StatInfo()
  34. build() {
  35. Column({ space: 10 }) {
  36. // 1.任务进度卡片
  37. TaskStatistics()
  38. // 2.任务列表
  39. TaskList()
  40. }
  41. .width('100%')
  42. .height('100%')
  43. .backgroundColor('#F1F2F3')
  44. }
  45. }
  46. @Component
  47. struct TaskStatistics {
  48. // 统计信息
  49. @Consume stat: StatInfo
  50. build() {
  51. // 1.任务进度卡片
  52. Row() {
  53. Text('任务进度')
  54. .fontSize(30)
  55. .fontWeight(FontWeight.Bold)
  56. // Stack 堆叠容器
  57. Stack() {
  58. // 进度条
  59. Progress({
  60. value: this.stat.finishTask,
  61. total: this.stat.totalTask,
  62. type: ProgressType.Ring
  63. })
  64. .width(100)
  65. Row() {
  66. Text(this.stat.finishTask.toString())
  67. .fontSize(24)
  68. .fontColor(Color.Blue)
  69. Text(' / ' + this.stat.totalTask.toString())
  70. .fontSize(24)
  71. }
  72. }
  73. }.card()
  74. .margin({ top: 20, bottom: 10 })
  75. .justifyContent(FlexAlign.SpaceEvenly)
  76. }
  77. }
  78. @Component
  79. struct TaskList {
  80. // 统计信息
  81. @Consume stat: StatInfo
  82. // 任务数组
  83. @State tasks: Task[] = []
  84. handleTaskChange() {
  85. // 1.更新任务总数量
  86. this.stat.totalTask = this.tasks.length
  87. // 2.更新已完成任务数量
  88. this.stat.finishTask = this.tasks.filter(item => item.finished).length
  89. }
  90. build() {
  91. Column() {
  92. // 2.新增任务按钮
  93. Button('新增任务')
  94. .width(200)
  95. .onClick(() => {
  96. // 1)新增任务数据
  97. this.tasks.push(new Task())
  98. // 2)更新
  99. this.handleTaskChange()
  100. })
  101. // 3.任务列表
  102. List({ space: 10 }) {
  103. ForEach(
  104. this.tasks,
  105. (item: Task, index) => {
  106. ListItem() {
  107. Row() {
  108. Text(item.name)
  109. .fontSize(20)
  110. // 多选框工具
  111. Checkbox()
  112. .select(item.finished)
  113. .onChange(val => {
  114. // 1)更新当前任务状态
  115. item.finished = val
  116. // 2)更新
  117. this.handleTaskChange()
  118. })
  119. }
  120. .card()
  121. .layoutWeight(1)
  122. .justifyContent(FlexAlign.SpaceBetween)
  123. }
  124. .swipeAction({ end: this.DeleteButton(index) })
  125. }
  126. )
  127. }
  128. .width('100%')
  129. .alignListItem(ListItemAlign.Center)
  130. }
  131. }
  132. @Builder DeleteButton(index: number) {
  133. Button() {
  134. Image($r('app.media.ic_public_list_deleted'))
  135. .fillColor(Color.White)
  136. .width(20)
  137. }
  138. .width(40)
  139. .height(40)
  140. .type(ButtonType.Circle)
  141. .backgroundColor(Color.Red)
  142. .margin(5)
  143. .onClick(() => {
  144. this.tasks.splice(index, 1)
  145. this.handleTaskChange()
  146. })
  147. }
  148. }

四、@Observed和@ObjectLink

@Observed和@ObjectLink装饰器用于涉及嵌套对象或数组元素为对象的场景中进行双向数据同步

  1. // 任务类 ———— 一般是放在单独的文件中然后导入
  2. @Observed
  3. class Task {
  4. // 静态变量,类中所有对象共享
  5. static id: number = 1
  6. // 任务名称
  7. name: string = `任务${Task.id++}`
  8. // 任务状态:是否完成
  9. finished: boolean = false
  10. }
  11. // 统一的卡片样式
  12. @Styles function card() {
  13. .width("95%")
  14. .padding(20)
  15. .backgroundColor(Color.White)
  16. .borderRadius(15)
  17. .shadow({ radius: 6, color: '#1F000000', offsetX: 2, offsetY: 4 })
  18. }
  19. // 任务完成样式
  20. @Extend(Text) function finishedTask() {
  21. .decoration({ type: TextDecorationType.LineThrough })
  22. .fontColor('#B1B2B1')
  23. }
  24. class StatInfo {
  25. // 总任务数
  26. totalTask: number = 0
  27. //已完成任务数
  28. finishTask: number = 0
  29. }
  30. @Entry
  31. @Component
  32. struct PropPage {
  33. // 统计信息
  34. @Provide stat: StatInfo = new StatInfo()
  35. build() {
  36. Column({ space: 10 }) {
  37. // 1.任务进度卡片
  38. TaskStatistics()
  39. // 2.任务列表
  40. TaskList()
  41. }
  42. .width('100%')
  43. .height('100%')
  44. .backgroundColor('#F1F2F3')
  45. }
  46. }
  47. @Component
  48. struct TaskStatistics {
  49. // 统计信息
  50. @Consume stat: StatInfo
  51. build() {
  52. // 1.任务进度卡片
  53. Row() {
  54. Text('任务进度')
  55. .fontSize(30)
  56. .fontWeight(FontWeight.Bold)
  57. // Stack 堆叠容器
  58. Stack() {
  59. // 进度条
  60. Progress({
  61. value: this.stat.finishTask,
  62. total: this.stat.totalTask,
  63. type: ProgressType.Ring
  64. })
  65. .width(100)
  66. Row() {
  67. Text(this.stat.finishTask.toString())
  68. .fontSize(24)
  69. .fontColor(Color.Blue)
  70. Text(' / ' + this.stat.totalTask.toString())
  71. .fontSize(24)
  72. }
  73. }
  74. }.card()
  75. .margin({ top: 20, bottom: 10 })
  76. .justifyContent(FlexAlign.SpaceEvenly)
  77. }
  78. }
  79. @Component
  80. struct TaskList {
  81. // 统计信息
  82. @Consume stat: StatInfo
  83. // 任务数组
  84. @State tasks: Task[] = []
  85. handleTaskChange() {
  86. // 1.更新任务总数量
  87. this.stat.totalTask = this.tasks.length
  88. // 2.更新已完成任务数量
  89. this.stat.finishTask = this.tasks.filter(item => item.finished).length
  90. }
  91. build() {
  92. Column() {
  93. // 2.新增任务按钮
  94. Button('新增任务')
  95. .width(200)
  96. .onClick(() => {
  97. // 1)新增任务数据
  98. this.tasks.push(new Task())
  99. // 2)更新
  100. this.handleTaskChange()
  101. })
  102. // 3.任务列表
  103. List({ space: 10 }) {
  104. ForEach(
  105. this.tasks,
  106. (item: Task, index) => {
  107. ListItem() {
  108. // 传方法handleTaskChange不加() 调用方法加() bind把父组件的this绑定到方法上
  109. TaskItem({ item: item, onTaskChange: this.handleTaskChange.bind(this) })
  110. }
  111. .swipeAction({ end: this.DeleteButton(index) })
  112. }
  113. )
  114. }
  115. .width('100%')
  116. .alignListItem(ListItemAlign.Center)
  117. }
  118. }
  119. @Builder DeleteButton(index: number) {
  120. Button() {
  121. Image($r('app.media.ic_public_list_deleted'))
  122. .fillColor(Color.White)
  123. .width(20)
  124. }
  125. .width(40)
  126. .height(40)
  127. .type(ButtonType.Circle)
  128. .backgroundColor(Color.Red)
  129. .margin(5)
  130. .onClick(() => {
  131. this.tasks.splice(index, 1)
  132. this.handleTaskChange()
  133. })
  134. }
  135. }
  136. @Component
  137. struct TaskItem {
  138. @ObjectLink item: Task
  139. onTaskChange: () => void
  140. build() {
  141. Row() {
  142. if (this.item.finished) {
  143. Text(this.item.name)
  144. .finishedTask()
  145. } else {
  146. Text(this.item.name)
  147. .fontSize(20)
  148. }
  149. // 多选框工具
  150. Checkbox()
  151. .select(this.item.finished)
  152. .onChange(val => {
  153. // 1)更新当前任务状态
  154. this.item.finished = val
  155. // 2)更新
  156. this.onTaskChange()
  157. })
  158. }
  159. .card()
  160. .layoutWeight(1)
  161. .justifyContent(FlexAlign.SpaceBetween)
  162. }
  163. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/333653
推荐阅读
相关标签
  

闽ICP备14008679号