当前位置:   article > 正文

鸿蒙入门06-常见装饰器( 简单装饰器 )

鸿蒙入门06-常见装饰器( 简单装饰器 )
  • 装饰器是鸿蒙开发中非常重要的一个环节
  • 因为在很多地方我们都需要用到装饰器
  • 并且如果我们想高度的复用, 那么装饰器就是必不可少的一环
  • 接下来我们就来介绍一些常见的装饰器
  • 注意 : 所有装饰器首字母大写

@Entry 

  • 用来装饰 struct 使用
  • 表示页面的入口

@Component 

  • 装饰 struct, 表示该 struct 具有基于组件的能力
  • 保证 struct 内部 包含一个且只能包含一个 build() 函数, 用于绘制 UI 界面
  • struct 内部, build() 函数外部, 用于存储数据的位置
  • 注意 : build() 函数内部必须要有容器组件
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. build() {
  6. /* 这里构建 UI 界面 */
  7. }
  8. }

 以上为基础内容结构

  • @Component 也可以单独定义组件
  • 单独定义的组件可以在其他组件内使用
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. build() {
  6. /* 这里构建 UI 界面 */
  7. Row() {
  8. /* 可以直接使用子组件 */
  9. SonCom()
  10. }
  11. }
  12. }
  13. // 定义一个子组件
  14. @Component
  15. struct SonCom {
  16. build() {
  17. /* 这里构建子组件 UI 结构 */
  18. }
  19. }

@State

  • 用来装饰变量的装饰器( 其实就是用于定义变量 )
  • 必须本地初始化数据, 支持通过构造函数赋值
  • 当 @State 定义的数据被修改的时候, 所在组件的 build() 方法会被重新调用, 重新绘制所在 UI 界面
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. @State count: number = 0
  6. build() {
  7. /* 这里构建 UI 界面 */
  8. Column() {
  9. // 展示 @state 定义的变量
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. // 按钮点击的时候修改 @state 定义的变量
  13. Button('Click Me').onClick(() => this.count++)
  14. }
  15. }
  16. }

这里使用 Text() 组件展示了 @State 定义的 count 变量

通过 Button() 组件的点击事件修改了 @State 定义的 count 变量

因为变量的修改导致了 UI 界面的重新绘制

所以页面跟随出现变化

其实就是我们之前知道的响应式数据一个原理

  • 在子组件内也同样是使用 @State 定义数据
  • 在子组件内定义的数据, 可以通过父组件调用的时候进行赋值

 

  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. @State count: number = 0
  6. build() {
  7. /* 这里构建 UI 界面 */
  8. Column() {
  9. Text('父组件 UI 部分').fontSize(20)
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. Button('Click Me').onClick(() => this.count++)
  13. Blank().height(30)
  14. Text('子组件 UI 部分')
  15. SonCom() // 不对初始内容进行赋值
  16. Blank().height(30)
  17. Text('子组件 UI 部分')
  18. SonCom({ count: 100 }) // 对初始内容进行赋值
  19. }
  20. }
  21. }
  22. @Component
  23. struct SonCom {
  24. @State count: number = 0
  25. build() {
  26. Column() {
  27. Text(`${ this.count }`).fontSize(20)
  28. }
  29. }
  30. }

当你调用子组件的时候

如果不对 @State 定义的变量赋值, 那么就用子组件内初始化时候的赋值

如果对 @State 定义的变量赋值, 那么就会使用调用时所赋予的值

  • 通过 @State 在子组件内进行赋值
  • 父子组件是互不干扰的, 数据是相互独立的
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. @State count: number = 0
  6. build() {
  7. /* 这里构建 UI 界面 */
  8. Column() {
  9. Text('父组件 UI 部分').fontSize(20)
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  13. Blank().height(30)
  14. Text('子组件 UI 部分')
  15. SonCom()
  16. }
  17. }
  18. }
  19. @Component
  20. struct SonCom {
  21. @State count: number = 0
  22. build() {
  23. Column() {
  24. Text(`${ this.count }`).fontSize(20)
  25. Divider().margin(10)
  26. Button('Click Me 修改子组件 count').onClick(() => this.count++)
  27. }
  28. }
  29. }

@Prop

  • 继承了 @State 的所有功能
  • 注意 :
    • 定义的时候可以不需要本地直接初始化, 调用子组件的时候需要对其进行赋值
    • 被 @Prop 装饰的变量可以和父组件建立单向同步关系
    • @Prop 装饰的变量是可变的, 但是修改时不会同步回父组件, 当父组件的 @State 变化时, 本地修改的 @Prop 会被覆盖
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. @State count: number = 0
  6. build() {
  7. /* 这里构建 UI 界面 */
  8. Column() {
  9. Text('父组件 UI 部分').fontSize(20)
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  13. Blank().height(30)
  14. Text('子组件 UI 部分')
  15. // 调用自组件的时候, 将父组件 @State 定义的 count 赋值
  16. SonCom({ count: this.count })
  17. }
  18. }
  19. }
  20. @Component
  21. struct SonCom {
  22. // 使用 @Prop 定义一个初始变量
  23. @Prop count: number
  24. build() {
  25. Column() {
  26. Text(`${ this.count }`).fontSize(20)
  27. Divider().margin(10)
  28. Button('Click Me 修改子组件 count').onClick(() => this.count++)
  29. }
  30. }
  31. }

  • 此时, 当你在子组件内修改 count 的时候, 子组件内的数据单独出现变换
  • 但是当你在父组件内修改 count 的时候, 会连带修改子组件内的 count, 并且会将覆盖子组件内的修改

@Link

  • @Link 装饰的变量和父组件会构建双向同步关系
    • 父组件会接受来自 @Link 装饰的变量的修改同步
    • 父组件的更新也会同步给 @Link 装饰的变量
  • @Link 装饰的变量与其父组件中的数据源共享相同的值
  • 注意 :
    • 子组件使用 @Link 定义变量的时候不需要赋值, 而是调用子组件的时候进行赋值
    • 调用子组件赋值的时候使用 "$变量名" 的形式进行赋值
    • @Link 装饰器不能再 @Entry 装饰的自定义组件中使用
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. @State count: number = 0
  6. build() {
  7. /* 这里构建 UI 界面 */
  8. Column() {
  9. Text('父组件 UI 部分').fontSize(20)
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  13. Blank().height(30)
  14. Text('子组件 UI 部分')
  15. // 调用自组件的时候, 将父组件 @State 定义的 count 赋值
  16. // 注意: 使用 $变量名 的形式进行赋值
  17. SonCom({ count: $count })
  18. }
  19. }
  20. }
  21. @Component
  22. struct SonCom {
  23. // 使用 @Link 定义一个初始变量
  24. @Link count: number
  25. build() {
  26. Column() {
  27. Text(`${ this.count }`).fontSize(20)
  28. Divider().margin(10)
  29. Button('Click Me 修改子组件 count').onClick(() => this.count++)
  30. }
  31. }
  32. }

  • 此时, 子组件内修改 count 的时候, 会同步影响到父组件内的 count
  • 修改父组件内的 count 的时候, 也会同步影响到子组件内的 count

@Provide 和 @Consume

  • 之前我们学习过了 @State/@Link 两个装饰器组合在一起, 可以实现父子组件的双向数据传递
  • 如果在父子组件之间进行数据传递的话, 使用起来还是相当方便的
  • 但是, 如果层级过高的话, 那么使用起来就比较麻烦来
  • 我们先来看一下 @State/@Link 进行层级组件嵌套
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. @State count: number = 0
  6. build() {
  7. Column() {
  8. Text('父组件 UI 部分').fontSize(20)
  9. Text(`${ this.count }`).fontSize(20)
  10. Divider().margin(10)
  11. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  12. Blank().height(30)
  13. Text('子组件 UI 部分')
  14. // 调用子组件的时候, 将父组件 @State 定义的 count 赋值
  15. // 注意: 使用 $变量名 的形式进行赋值
  16. SonCom({ count: $count })
  17. }
  18. }
  19. }
  20. @Component
  21. struct SonCom {
  22. // 使用 @Link 定义一个初始变量
  23. @Link count: number
  24. build() {
  25. Column() {
  26. Text(`${ this.count }`).fontSize(20)
  27. Divider().margin(10)
  28. Button('Click Me 修改子组件 count').onClick(() => this.count++)
  29. Blank().height(30)
  30. Text('子子组件 UI 部分')
  31. // 调用子子组件的时候, 将子组件 @Link 定义的 count 赋值
  32. // 注意: 使用 $变量名 的形式进行赋值
  33. SonSonCom({ count: $count })
  34. }
  35. }
  36. }
  37. @Component
  38. struct SonSonCom {
  39. // 使用 @Link 定义一个初始变量
  40. @Link count: number
  41. build() {
  42. Column() {
  43. Text(`${ this.count }`).fontSize(20)
  44. Divider().margin(10)
  45. Button('Click Me 修改子组件 count').onClick(() => this.count++)
  46. }
  47. }
  48. }

 

  • 此时我们就实现了跨组件传递数据
  • 但是想对来说就比较麻烦了, 相当繁琐
  • 如果组件嵌套的层级过深, 那么这个数据的传递就实在是太复杂了
  • 此时我们可以使用 @Provide 和 @Consume 进行跨组件数据传递
  • 使用语法 :
    • @Provide('名字') 变量名: 类型 = 赋值
    • @Consume('名字') 变量名
    • 注意 : @Provide 和 @Comsume 处使用的名字要一致, 但是变量名不需要一致

  • 使用发布订阅模式, 父类使用 @Provide, 其他需要观察的子类使用 @Consume, 就可以实现双向绑定
  • 当层级很深时, 不需要一层一层传递数据, 直接使用发布订阅进行监听就能实现相同的效果
  • @Provide 和 @Consume 可以通过相同的变量名或者相同的变量别名绑定, 但是变量类型必须相同
  • @Provide 必须设置初始值, @Consume 不可以设置默认初始值
  • @Provide 修饰的变量和 @Consume 修饰的变量可以是一对多的关系

@Watch

  • 使用观察者模式的装饰器
  • 注意 : 该装饰器不是触发变量变化, 而是绑定一个函数, 当监控的变量发生变化时, 该函数触发
  • 语法 : @Watch('函数名')
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. // 在父组件内使用 @Provide 创建数据
  6. @State count: number = 0
  7. build() {
  8. Column() {
  9. Text('父组件 UI 部分').fontSize(20)
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  13. Blank().height(30)
  14. Text('子组件 UI 部分')
  15. SonCom({ count: this.count })
  16. }
  17. }
  18. }
  19. @Component
  20. struct SonCom {
  21. @Prop @Watch('onCountUpdate') count: number
  22. onCountUpdate(): void {
  23. console.log('count 数据发生变化了')
  24. }
  25. build() {
  26. Column() {
  27. Text(`${ this.count }`).fontSize(20)
  28. Divider().margin(10)
  29. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  30. }
  31. }
  32. }

@Builder

  • @Builder 是 ArkUI 提供的一种更加轻量的复用机制
  • 因为在 @Component 内能且只能创建一个 build() 函数
  • 我们可以在组件内利用 @Builder 装饰器自定义一个构建函数
  • @Builder 创建的构建函数遵循 build() 函数的语法规则, 并且可以在 build() 函数内调用
  • 语法 :
    • 定义语法 : @Builder MyBuilder() {}
    • 使用语法 : this.MyBuilder() {}
  • 语法要点
    • 自定义构建函数可以在所属组件内的 build() 方法和其他自定义构建函数内调佣, 但不允许在组件外调用
    • 允许在自定义组件内定义一个或多个 @Builder 方法, 该方法被认为是该组件的私有成员
    • 在自定义函数体内, this 指代当前所属组件, 组件的状态变量可以在自定义构建函数内访问
    • 自定义构建函数不仅可以添加属性, 还可以添加事件

  • 在组件外也可以使用 @Builder 创建一个自定义构建函数
  • 注意 : 在组件外使用 @Builder 的时候, 构建函数内不能使用 this
  1. @Entry
  2. @Component
  3. struct Index {
  4. /* 这里存放数据 */
  5. // 在父组件内使用 @Provide 创建数据
  6. @State count: number = 0
  7. // 创建一段组件内自定义构建函数
  8. @Builder CountUpdate() {
  9. Text('父组件 UI 部分').fontSize(20)
  10. Text(`${ this.count }`).fontSize(20)
  11. Divider().margin(10)
  12. Button('Click Me 修改父组件 count').onClick(() => this.count++)
  13. }
  14. build() {
  15. Column() {
  16. // 直接使用自定义构建函数
  17. this.CountUpdate()
  18. Blank().height(30)
  19. // 使用组件外自定义构建函数
  20. MyBuilder('Hello World')
  21. }
  22. }
  23. }
  24. // 组件外定义自定义构建函数
  25. @Builder
  26. function MyBuilder(message: string) {
  27. Column() {
  28. Text(message)
  29. }
  30. }

@Styles

  • 在开发中有的时候, 有的时候我们的一些样式也要重用
  • @Styles 装饰器就可以将多条样式提炼成一个方法, 以供复用
  • 和 @Builder 一样, 可以定义在 组件内 和 组件外
  1. @Entry
  2. @Component
  3. struct Index {
  4. // 定义一个组件内样式方法
  5. @Styles MyStyles() {
  6. .width(200)
  7. .height(200)
  8. .backgroundColor(Color.Orange)
  9. }
  10. build() {
  11. Column() {
  12. Row() {}.MyStyles()
  13. Blank().margin(10)
  14. Row() {}.MyStyles()
  15. }
  16. }
  17. }

  • 这是组件内定义样式方法
  • 我们再来定义一个组件外样式方法
  1. @Entry
  2. @Component
  3. struct Index {
  4. // 定义一个组件内样式方法
  5. @Styles MyStyles() {
  6. .width(200)
  7. .height(200)
  8. .backgroundColor(Color.Orange)
  9. }
  10. build() {
  11. Column() {
  12. Row() {}.MyStyles()
  13. Blank().margin(10)
  14. Row() {}.MyStyles2()
  15. }
  16. }
  17. }
  18. @Styles
  19. function MyStyles2() {
  20. .width(100)
  21. .height(100)
  22. .backgroundColor(Color.Pink)
  23. }

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

闽ICP备14008679号