当前位置:   article > 正文

ArkTS @Observed、@ObjectLink状态装饰器的使用_arkts observed

arkts observed

 作用

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

状态的使用

1.嵌套对象

我们将父类设置为@Observed状态,这个时候,子应该设置@ObjectLink才能完成数据的双向绑定,所以我们构建一个组件,让状态变成一个变量来完成属性的状态化。

  1. @Observed
  2. class Person{
  3. name: string
  4. age: number
  5. gf: Person
  6. constructor(name:string, age: number, gf?: Person) {
  7. this.name = name
  8. this.age = age
  9. this.gf = gf
  10. }
  11. }
  12. @Entry
  13. @Component
  14. struct Parent {
  15. @State p: Person = new Person('zhangsan',21,new Person('lisi',18))
  16. build() {
  17. Row() {
  18. Column() {
  19. Child({p:this.p.gf})
  20. .onClick(()=>this.p.gf.age++)
  21. }
  22. .width('100%')
  23. }
  24. .height('100%')
  25. }
  26. }
  27. @Component
  28. struct Child{
  29. @ObjectLink p: Person
  30. build(){
  31. Column(){
  32. Text(`${this.p.name} : ${this.p.age}`)
  33. }
  34. }
  35. }

2.数组中的对象元素

只要我们的数据 经过了Child的手,也就是使用了@ObjectLink绑定的变量,变量状态的更新都会直接出发视图的更新。

  1. @Observed
  2. class Person{
  3. name: string
  4. age: number
  5. gf: Person
  6. constructor(name:string, age: number, gf?: Person) {
  7. this.name = name
  8. this.age = age
  9. this.gf = gf
  10. }
  11. }
  12. @Entry
  13. @Component
  14. struct Parent {
  15. @State p: Person = new Person('zhangsan',21,new Person('lisi',18))
  16. @State gfs: Person[] = [
  17. new Person('wangwu',18),new Person('yangliu',19), ]
  18. build() {
  19. Row() {
  20. Column() {
  21. Child({p:this.p.gf})
  22. .onClick(()=>this.p.gf.age++)
  23. Text('===== 列表 =====')
  24. ForEach(
  25. this.gfs,
  26. p=> {
  27. Child({p:p}).onClick(()=>p.age++)
  28. }
  29. )
  30. }
  31. .width('100%')
  32. }
  33. .height('100%')
  34. }
  35. }
  36. @Component
  37. struct Child{
  38. @ObjectLink p: Person
  39. build(){
  40. Column(){
  41. Text(`${this.p.name} : ${this.p.age}`)
  42. }
  43. }
  44. }

 任务统计案例验证

我们在任务统计案例中使用一下这两个状态。

我们现在想要实现一个效果,就是已经完成的任务,让他变成灰色,并且加删除线效果。

  1. // 任务完成样式
  2. @Extend(Text) function finishedTask(){
  3. .decoration({type:TextDecorationType.LineThrough})
  4. .fontColor('#b1b2b1')
  5. }
  6. Row(){
  7. if(item.finished){
  8. Text(item.name)
  9. .finishedTask()
  10. }else{
  11. Text(item.name)
  12. }
  13. Checkbox()
  14. .select(item.finished)
  15. .onChange(val=>{
  16. item.finished = val
  17. // 通过过滤方法 更新已完成的任务数量
  18. this.handleTaskChange()
  19. })
  20. }

我们通过if判断每个任务的状态来决定使用哪种效果,发现不能实现我们的效果。因为foreach遍历数组,等同于给数组元素的属性来改变,正巧我们要修改的属性是一个对象,所以我们的修改是不会触发视图的更新的,所以我们应该使用@Observed、@ObjectLink状态来完成这个案例。 

所以我们来给需要实现的嵌套数组的对象加上状态。

我们给最原始的类Task加上@Observed状态,封装循环产生的Row给item加上@ObjectLink状态,由于我们的组件中,没有状态改变的函数,我们先去掉,先完成样式的修改。

  1. @Observed
  2. class Task{
  3. static id: number = 1
  4. // 任务名称
  5. name: string = `任务${Task.id++}`
  6. // 任务状态: 是否完成
  7. finished: boolean = false
  8. }
  9. // 统计的卡片样式
  10. @Styles function card(){
  11. .width('95%')
  12. .padding(20)
  13. .backgroundColor(Color.White)
  14. .borderRadius(15)
  15. .shadow({radius: 6,color: '#1f0000',offsetX:2,offsetY:4})
  16. }
  17. // 任务完成样式
  18. @Extend(Text) function finishedTask(){
  19. .decoration({type:TextDecorationType.LineThrough})
  20. .fontColor('#b1b2b1')
  21. }
  22. // 任务统计信息
  23. class StaticInfo{
  24. totalTask: number = 0
  25. finishTask: number = 0
  26. }
  27. @Entry
  28. @Component
  29. struct PropPage {
  30. // 统计信息
  31. @Provide stat: StaticInfo = new StaticInfo()
  32. build() {
  33. Column({space:10}) {
  34. // 1.任务进度卡片
  35. TaskStatistics()
  36. // 2.任务列表
  37. TaskList();
  38. }
  39. .width('100%')
  40. .height('100%')
  41. .backgroundColor('#f1f2f3')
  42. }
  43. }
  44. @Component
  45. struct TaskStatistics {
  46. @Consume stat: StaticInfo
  47. build(){
  48. Row(){
  49. Text("任务进度")
  50. .fontSize(30)
  51. .fontWeight(FontWeight.Bold)
  52. Stack(){
  53. Progress({
  54. value:this.stat.finishTask,
  55. total:this.stat.totalTask,
  56. type:ProgressType.Ring
  57. })
  58. .width(100)
  59. Row(){
  60. Text(this.stat.finishTask.toString())
  61. .fontSize(24)
  62. .fontColor('#36d')
  63. Text(' / ' +this.stat.totalTask.toString())
  64. .fontSize(24)
  65. }
  66. }
  67. }
  68. .card()
  69. .margin({top:20,bottom:10})
  70. .justifyContent(FlexAlign.SpaceEvenly)
  71. }
  72. }
  73. @Component
  74. struct TaskList {
  75. // 任务数量
  76. @State tasks: Task[] = []
  77. @Consume stat: StaticInfo
  78. // 通过过滤方法 更新已完成的任务数量
  79. handleTaskChange(){
  80. // 更新任务总数量
  81. this.stat.totalTask = this.tasks.length
  82. // 已经完成的任务数量
  83. this.stat.finishTask = this.tasks.filter(item => item.finished).length
  84. }
  85. build(){
  86. Column(){
  87. // 2.新增任务按钮
  88. Button('新增任务')
  89. .width(200)
  90. .onClick(()=>{
  91. // 1.新增任务
  92. this.tasks.push(new Task())
  93. // 2.更新任务数组
  94. this.stat.totalTask = this.tasks.length
  95. })
  96. // 3.卡片列表
  97. List({space:10}){
  98. ForEach(
  99. this.tasks,
  100. (item: Task,index)=>{
  101. ListItem(){
  102. TaskItem({item:item})
  103. }
  104. .swipeAction({end:this.DeleteButton(index)})
  105. }
  106. )
  107. }
  108. .width('100%')
  109. .layoutWeight(1)
  110. .alignListItem(ListItemAlign.Center)
  111. }
  112. }
  113. @Builder DeleteButton(index: number){
  114. Button("删除")
  115. .onClick(()=>{
  116. this.tasks.splice(index,1)
  117. this.handleTaskChange()
  118. })
  119. }
  120. }
  121. @Component
  122. struct TaskItem {
  123. @ObjectLink item: Task
  124. build(){
  125. Row(){
  126. if(this.item.finished){
  127. Text(this.item.name)
  128. .finishedTask()
  129. }else{
  130. Text(this.item.name)
  131. }
  132. Checkbox()
  133. .select(this.item.finished)
  134. .onChange(val=>{
  135. this.item.finished = val
  136. // 通过过滤方法 更新已完成的任务数量
  137. // this.handleTaskChange()
  138. })
  139. }
  140. .card()
  141. .justifyContent(FlexAlign.SpaceBetween)
  142. }
  143. }

我们会发现 点击我们的完成勾选,我们的颜色还有删除线的状态是成功的体现出来的,所以我们的嵌套数组双向绑定是成功的。

现在我们来补全功能,更新我们的完成状态。

方法传递

我们可以通过方法传递来实现方法的公用。

 

  1. @Component
  2. struct TaskItem {
  3. @ObjectLink item: Task
  4. onTaskChange: () => void
  5. build(){
  6. Row(){
  7. if(this.item.finished){
  8. Text(this.item.name)
  9. .finishedTask()
  10. }else{
  11. Text(this.item.name)
  12. }
  13. Checkbox()
  14. .select(this.item.finished)
  15. .onChange(val=>{
  16. this.item.finished = val
  17. // 通过过滤方法 更新已完成的任务数量
  18. this.onTaskChange();
  19. })
  20. }
  21. .card()
  22. .justifyContent(FlexAlign.SpaceBetween)
  23. }
  24. }

我们在taskItem方法中写入一个函数,在调用的时候将函数传入。 这样就相当于我们在taskItem中调用了这个方法。 

然后我们会发现仍然没有实现。因为在子组件中this的指向不正确。

当方法传递的时候,this的指向要确认,因为调方法的人改变了。

所以我们要确保传递方法的时候,this的指向不能改变。这时候我们需要使用到一个api

bind(this)

这时候我们就可以完全实现效果了。 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号