【鸿蒙学习笔记】@Prop装饰器:父子单向同步

官方文档:@Prop装饰器:父子单向同步

[Q&A] @Prop装饰器作用

@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。

[Q&A] @Prop装饰器特点

1・@Prop装饰器不能在@Entry装饰的自定义组件中使用。

2・@Prop装饰变量时会进行深拷贝,在拷贝的过程中除了基本类型、Map、Set、Date、Array外,都会丢失类型。

样例1:Date

cpp 复制代码
@Component
struct DateComponent {
  @Prop childSelectedDate: Date = new Date('');

  build() {
    Column() {
      Row() {
        Button('child +1年').margin(5).width('30%')
          .onClick(() => {
            this.childSelectedDate.setFullYear(this.childSelectedDate.getFullYear() + 1)
          })
        Button('child +1月').margin(5).width('30%')
          .onClick(() => {
            this.childSelectedDate.setMonth(this.childSelectedDate.getMonth() + 1)
          })
        Button('child +1天').margin(5).width('30%')
          .onClick(() => {
            this.childSelectedDate.setDate(this.childSelectedDate.getDate() + 1)
          })
      }.width('100%')

      Button('child 重置日期').margin(10).width('100%')
        .onClick(() => {
          this.childSelectedDate = new Date('2023-07-07')
        })

      DatePicker({
        start: new Date('1970-1-1'),
        end: new Date('2100-1-1'),
        selected: this.childSelectedDate
      })
    }
  }
}

@Entry
@Component
struct SizeExample {
  @State parentSelectedDate: Date = new Date('2008-08-08');

  build() {
    Column() {
      Row() {
        Button('parent +1年').margin(5).width('30%')
          .onClick(() => {
            this.parentSelectedDate.setFullYear(this.parentSelectedDate.getFullYear() + 1)
          })
        Button('parent +1月').margin(5).width('30%')
          .onClick(() => {
            this.parentSelectedDate.setMonth(this.parentSelectedDate.getMonth() + 1)
          })
        Button('parent +1天').margin(5).width('30%')
          .onClick(() => {
            this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1)
          })
      }.width('100%')

      Button('parent 重置日期').margin(10).width('100%')
        .onClick(() => {
          this.parentSelectedDate = new Date('2023-07-07')
        })

      DatePicker({
        start: new Date('1970-1-1'),
        end: new Date('2100-1-1'),
        selected: this.parentSelectedDate
      })
      DateComponent({ childSelectedDate: this.parentSelectedDate })
    }
  }
}

样例2:父组件@State简单数据类型→子组件@Prop简单数据类型同步

cpp 复制代码
@Component
struct CountDownComponent {
  @Prop count: number = 0;
  costOfOneAttempt: number = 1;

  build() {
    Row() {
      if (this.count > 0) {
        Text(`当前值为 ${this.count} .`).fontSize(20).margin(10).textAlign(TextAlign.Center)
      } else {
        Text('Game over!').fontSize(20).margin(10)
      }
      Button('子 -1').onClick(() => {
        this.count -= this.costOfOneAttempt;
      }).width("40%")
    }.width('100%')
  }
}

@Entry
@Component
struct SizeExample {
  @State countDownStartValue: number = 10;

  build() {
    Column() {
      Row() {
        if (this.countDownStartValue > 0) {
          Text(`当前值为 ${this.countDownStartValue} .`).fontSize(20).margin(5).textAlign(TextAlign.Center)
        } else {
          Text('Game over!').fontSize(20).margin(10)
        }

        Button('父 +1 ').onClick(() => {
          this.countDownStartValue += 1;
        }).margin(5).width("20%")

        Button('父 -1 ').onClick(() => {
          this.countDownStartValue -= 1;
        }).margin(5).width("20%")
      }.width('100%')

      CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
    }
  }
}

样例3:父组件@State数组项→子组件@Prop简单数据类型同步

cpp 复制代码
@Component
struct Child {
  @Prop value: number = 0;

  build() {
    Text(`${this.value}`).fontSize(30)
      .onClick(() => {
        this.value++
      })
  }
}

@Entry
@Component
struct SizeExample {
  @State arr: number[] = [1, 2, 3];

  build() {
    Row() {

      Column() {
        Text(`当前值为 ${this.arr[0]},${this.arr[1]},${this.arr[2]}.`).fontSize(30).margin(10).textAlign(TextAlign.Center)

        Divider().height(10)

        Row() {
          Child({ value: this.arr[0] }).width('30%').align(Alignment.Center).backgroundColor(Color.Red)
          Child({ value: this.arr[1] }).width('30%').align(Alignment.Center).backgroundColor(Color.Green)
          Child({ value: this.arr[2] }).width('30%').align(Alignment.Center).backgroundColor(Color.Yellow)
        }.alignItems(VerticalAlign.Center)

        Divider().height(10)

        Row() {
          ForEach(this.arr, (item: number) => {
            Child({ value: item }).width('30%').align(Alignment.Center).backgroundColor(Color.Orange).border({ width: 1, style: BorderStyle.Dashed })
          }, (item: string) => item.toString())
        }.alignItems(VerticalAlign.Center)

        Divider().height(10)

        Text('重置').fontSize(30).backgroundColor(Color.Pink).width('50%').textAlign(TextAlign.Center).padding(10)
          .onClick(() => {
            // 两个数组都包含项"3"。
            this.arr = this.arr[0] == 1 ? [3, 4, 5] : [1, 2, 3];
          })
      }
    }
  }
}

样例4:父组件@State类对象属性→@Prop简单类型的同步

cpp 复制代码
class Book {
  public title: string;
  public pages: number;
  public readIt: boolean = false;

  constructor(title: string, pages: number) {
    this.title = title;
    this.pages = pages;
  }
}

@Component
struct ReaderComp {
  @Prop book: Book = new Book("", 0);

  build() {
    Row() {
      Text(this.book.title).fontSize(20)
      Text(` 有 ${this.book.pages} 页! `).fontSize(20)
      Text(`${this.book.readIt ? " 我读了" : ' 我还没开始读'}`).fontSize(20)
        .onClick(() => this.book.readIt = true).backgroundColor(Color.Pink)
    }
  }
}

@Entry
@Component
struct SizeExample {
  @State book: Book = new Book('资治通鉴', 765);

  build() {
    Column() {
      ReaderComp({ book: this.book })
      ReaderComp({ book: this.book })
    }
  }
}

样例5:父组件@State数组项→@Prop class类型的同步

cpp 复制代码
let nextId: number = 1;

@Observed // @Prop在子组件装饰的状态变量和父组件的数据源是单向同步关系,需要使用@Observed装饰class Book,Book的属性将被观察。
class Book {
  public id: number;
  public title: string;
  public pages: number;
  public readIt: boolean = false;

  constructor(title: string, pages: number) {
    this.id = nextId++;
    this.title = title;
    this.pages = pages;
  }
}

@Component
struct ReaderComp {
  @Prop book: Book = new Book("", 1);

  build() {
    Row() {
      Text(` ${this.book ? this.book.title : "未定义"}`).fontColor(Color.Red)
      Text(` 有 ${this.book ? this.book.pages : "未定义"} 页!`).fontColor(Color.Black)
      Text(` ${this.book ? (this.book.readIt ? "我已经读了" : '我还没读' ): "未定义"}`).fontColor(Color.Blue)
        .onClick(() => this.book.readIt = true)
    }
  }
}

@Entry
@Component
struct SizeExample {
  @State allBooks: Book[] = [new Book("资治通鉴", 100), new Book("史记", 100), new Book("论语", 100)];

  build() {
    Column() {
      Text('畅销书').width(312).height(40).fontSize(20).margin(12).fontColor('#e6000000')
      ReaderComp({ book: this.allBooks[2] }).backgroundColor('#0d000000').width(312).height(40).padding({ left: 20, top: 10 }).borderRadius(20).colorBlend('#e6000000')

      Divider()

      Text('已经购买的书').width(312).height(40).fontSize(20).margin(12).fontColor('#e6000000')
      ForEach(this.allBooks, (book: Book) => {
        ReaderComp({ book: book }).margin(12).width(312).height(40).padding({ left: 20, top: 10 }).backgroundColor('#0d000000').borderRadius(20)
      },(book: Book) => book.id.toString())

      Button('追加').width(312).height(40).margin(12).fontColor('#FFFFFF 90%')
        .onClick(() => {
          this.allBooks.push(new Book("孟子", 100));
        })

      Button('移除第一本书').width(312).height(40).margin(12).fontColor('#FFFFFF 90%')
        .onClick(() => {
          if (this.allBooks.length > 0){
            this.allBooks.shift();
          } else {
            console.log("length <= 0")
          }
        })

      Button("所有人都已经读了").width(312).height(40).margin(12).fontColor('#FFFFFF 90%')
        .onClick(() => {
          this.allBooks.forEach((book) => book.readIt = true)
        })
    }
  }
}

样例6:@Prop本地初始化不和父组件同步

cpp 复制代码
@Component
struct MyComponent {
  @Prop count1: number;
  @Prop count2: number = 5;

  build() {
    Column() {
      Row() {
        Text(`Parent: ${this.count1}`).fontColor('#ff6b6565').width('30%')
        Text(`Child: ${this.count2}`).fontColor('#ff6b6565').width('30%')
        Button('改变Child数值').width('30%').height(40).fontColor('#FFFFFF,90%')
          .onClick(() => {
            this.count2++
          })
      }
    }
  }
}

@Entry
@Component
struct SizeExample {
  @State mainCount: number = 10;

  build() {
    Column() {
      Row() {
        Column() {
          MyComponent({ count1: this.mainCount })
          Divider().height(10)
          MyComponent({ count1: this.mainCount, count2: this.mainCount })
        }
      }

      Divider().height(10)

      Column() {
        Button('改变Parent数值').width(288).height(40).width('100%').fontColor('#FFFFFF,90%')
          .onClick(() => {
            this.mainCount++
          })
      }
    }
  }
}

样例7:@Prop嵌套场景

几个按钮跳的乱,需要消化

cpp 复制代码
@Entry
@Component
struct SizeExample {
  @State book: Book = new Book('Book名字', new Title('Book标题'))

  build() {
    Column() {
      Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
        Text(this.book.name).fontSize(16).margin(12).width(312).height(40).backgroundColor(Color.Green).borderRadius(20).textAlign(TextAlign.Center).fontColor('#e6000000')
          .onClick(() => {
            this.book.name = '资治通鉴'
          })

        Text(this.book.title.title).fontSize(16).margin(12).width(312).height(40).backgroundColor(Color.Green).borderRadius(20).textAlign(TextAlign.Center)
          .onClick(() => {
            this.book.title.title = "资治通鉴 标题"
          })

        ShowTitle({ title: this.book.title })

        Button('修改 Book 名字').width(312).height(40).margin(12).fontColor('#FFFFFF,90%')
          .onClick(() => {
            this.book.name = "史记"
          })
        Button('修改 Book 标题').width(312).height(40).margin(12).fontColor('#FFFFFF,90%')
          .onClick(() => {
            this.book.title.title = "史记 标题"
          })
      }
    }
  }
}


@Component
struct ShowTitle {
  @Prop title: Title = new Title('');

  build() {
    Column() {
      Text(this.title.title).fontSize(16).margin(12).width(312).height(40).backgroundColor(Color.Orange).borderRadius(20).textAlign(TextAlign.Center)
        .onClick(() => {
          this.title.title = '点击完毕'
        })
    }
  }
}

// 以下是嵌套类对象的数据结构。
@Observed
class Title {
  public title: string;

  constructor(title: string) {
    this.title = title;
  }
}

@Observed
class Book {
  public name: string;
  public title: Title;

  constructor(name: string, cla: Title) {
    this.name = name;
    this.title = cla;
  }
}

样例8:装饰Map类型变量

cpp 复制代码
@Component
struct MapComponent {
  @Prop map: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])

  build() {
    Column() {
      ForEach(Array.from(this.map.entries()), (item: [number, string]) => {
        Row(){
          Text(`${item[0]}`).fontSize(30).margin(10)
          Text(`${item[1]}`).fontSize(30).margin(10)
        }
        Divider()
      })

      Button('初始化').margin(5).width('100%').onClick(() => {
        this.map = new Map([[0, "a"], [1, "b"], [3, "c"]])
      })
      Button('追加1组值').margin(5).width('100%').onClick(() => {
        this.map.set(4, "d")
      })
      Button('清除所有值').margin(5).width('100%').onClick(() => {
        this.map.clear()
      })
      Button('替换第1个值').margin(5).width('100%').onClick(() => {
        this.map.set(0, "aa")
      })
      Button('删除第1个值').margin(5).width('100%').onClick(() => {
        this.map.delete(0)
      })
    }
  }
}

@Entry
@Component
struct SizeExample {
  @State message: Map<number, string> = new Map([[1, "a"], [2, "b"], [3, "c"]])

  build() {
    Row() {
      Column() {
        MapComponent({ map: this.message })
      }.width('100%').backgroundColor(Color.Green)
    }.height('100%').backgroundColor(Color.Pink)
  }
}

样例9:装饰Set类型变量

cpp 复制代码
@Component
struct Child {
  @Prop message: Set<number> = new Set([0, 1, 2, 3, 4])

  build() {
    Column() {
      Row() {
        ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
          Text(`${item[0]}`).fontSize(30).margin(10)
        })
      }
      Button('初始化Set').width('100%').onClick(() => {
        this.message = new Set([0, 1, 2, 3, 4])
      })
      Divider().height(10)
      Button('追加新值').width('100%').onClick(() => {
        this.message.add(5)
      })
      Divider().height(10)
      Button('清除所有值').width('100%').onClick(() => {
        this.message.clear()
      })
      Divider().height(10)
      Button('删除第一个值').width('100%').onClick(() => {
        this.message.delete(0)
      })
    }.width('100%')
  }
}


@Entry
@Component
struct SizeExample {
  @State message: Set<number> = new Set([0, 1, 2, 3, 4])

  build() {
    Row() {
      Column() {
        Child({ message: this.message })
      }.width('100%')
    }.height('100%')
  }
}

样例10:Prop支持联合类型实例

cpp 复制代码
class Animals {
  public name: string;

  constructor(name: string) {
    this.name = name;
  }
}

@Component
struct Child {
  @Prop animal: Animals | undefined;

  build() {
    Column() {
      Text(`子  ${this.animal instanceof Animals ? this.animal.name : '未定义'}`).fontSize(20).backgroundColor(Color.Pink).width('100%').padding(5)

      Button('子 改为猫').width('100%').margin(5)
        .onClick(() => {
          // 赋值为Animals的实例
          this.animal = new Animals("猫")
        })

      Button('子 改为 undefined').width('100%').margin(5)
        .onClick(() => {
          // 赋值为undefined
          this.animal = undefined
        })

    }.width('100%')
  }
}

@Entry
@Component
struct SizeExample {
  @State animal: Animals | undefined = new Animals("老虎");

  build() {
    Column() {
      Text(`父  ${this.animal instanceof Animals ? this.animal.name : '未定义'}`).fontSize(20).textAlign(TextAlign.Start).backgroundColor(Color.Yellow).width('100%').padding(5)

      Child({ animal: this.animal })

      Button('父 改为狗').width('100%').margin(5)
        .onClick(() => {
          if (this.animal instanceof Animals) {
            this.animal.name = "狗"
          } else {
            console.info('num is undefined, cannot change property')
          }
        })

      Button('父 改为 undefined').width('100%').margin(5)
        .onClick(() => {
          this.animal = undefined
        })
    }.backgroundColor(Color.Orange)
  }
}
相关推荐
biter008816 分钟前
opencv(15) OpenCV背景减除器(Background Subtractors)学习
人工智能·opencv·学习
车轮滚滚__26 分钟前
uniapp对接unipush 1.0 ios/android
笔记
Code哈哈笑1 小时前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
QQ同步助手2 小时前
如何正确使用人工智能:开启智慧学习与创新之旅
人工智能·学习·百度
流浪的小新2 小时前
【AI】人工智能、LLM学习资源汇总
人工智能·学习
A懿轩A3 小时前
C/C++ 数据结构与算法【数组】 数组详细解析【日常学习,考研必备】带图+详细代码
c语言·数据结构·c++·学习·考研·算法·数组
云边有个稻草人3 小时前
【优选算法】—复写零(双指针算法)
笔记·算法·双指针算法
枫叶丹44 小时前
【HarmonyOS之旅】HarmonyOS开发基础知识(三)
华为od·华为·华为云·harmonyos
SoraLuna9 小时前
「Mac畅玩鸿蒙与硬件47」UI互动应用篇24 - 虚拟音乐控制台
开发语言·macos·ui·华为·harmonyos
南宫生11 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论