【鸿蒙学习笔记】@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)
  }
}
相关推荐
Mephisto.java24 分钟前
【大数据学习 | kafka高级部分】kafka中的选举机制
大数据·学习·kafka
Yawesh_best38 分钟前
思源笔记轻松连接本地Ollama大语言模型,开启AI写作新体验!
笔记·语言模型·ai写作
南宫生1 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
长弓三石1 小时前
鸿蒙网络编程系列44-仓颉版HttpRequest上传文件示例
前端·网络·华为·harmonyos·鸿蒙
武子康2 小时前
大数据-212 数据挖掘 机器学习理论 - 无监督学习算法 KMeans 基本原理 簇内误差平方和
大数据·人工智能·学习·算法·机器学习·数据挖掘
CXDNW2 小时前
【网络面试篇】HTTP(2)(笔记)——http、https、http1.1、http2.0
网络·笔记·http·面试·https·http2.0
使者大牙2 小时前
【大语言模型学习笔记】第一篇:LLM大规模语言模型介绍
笔记·学习·语言模型
ssf-yasuo2 小时前
SPIRE: Semantic Prompt-Driven Image Restoration 论文阅读笔记
论文阅读·笔记·prompt
As977_2 小时前
前端学习Day12 CSS盒子的定位(相对定位篇“附练习”)
前端·css·学习
ajsbxi3 小时前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet