#HarmonyOS篇:管理组件拥有的状态

官网链接 @Prop @Link等

@State

@State声明的变量,必须给初始值,否则编辑报错
不支持装饰Function类型。

@Prop

基本用法

@Prop装饰的变量允许本地修改,但修改不会同步回父组件。

子组件@Prop更新时,更新仅停留在当前子组件,不会同步回父组件。

不允许装饰Function类型

父组件传递的值 子组件不用@Prop接收也可以渲染,只不过子组件改值不会自动更新视图

使用a.b(this.object)形式调用,不会触发UI刷新

通过赋值添加 Proxy 代理 let score1 = this.score

js 复制代码
class Score {
  value: number;
  constructor(value: number) {
    this.value = value;
  }

  static changeScore1(score:Score) {
    score.value += 1;
  }
}

@Entry
@Component
struct Parent {
  @State score: Score = new Score(1);

  build() {
    Column({space:8}) {
      Text(`The value in Parent is ${this.score.value}.`)
        .fontSize(30)
        .fontColor(Color.Red)
      Child({ score: this.score })
    }
    .width('100%')
    .height('100%')
  }
}

@Component
struct Child {
  @Prop score: Score;

  changeScore2(score:Score) {
    score.value += 2;
  }

  build() {
    Column({space:8}) {
      Text(`The value in Child is ${this.score.value}.`)
        .fontSize(30)
      Button(`changeScore1`)
        .onClick(()=>{
          // 通过赋值添加 Proxy 代理
          let score1 = this.score;
          Score.changeScore1(score1);
        })
      Button(`changeScore2`)
        .onClick(()=>{
          // 通过赋值添加 Proxy 代理
          let score2 = this.score;
          this.changeScore2(score2);
        })
    }
  }
}
注意事项
  • List item

@Link装饰器不建议在@x`Entry装饰的自定义组件中使用,否则编译时会抛出警告;若该自定义组件作为页面根节点使用,则会抛出运行时错误。

  • @Link装饰的变量禁止本地初始化,否则编译期会报错。

  • @Link装饰的变量的类型要和数据源类型保持一致,否则编译期会报错。同时,数据源必须是状态变量,否则框架会抛出运行时错误。

  • @Link装饰的变量仅能被状态变量初始化,不能使用常规变量初始化,否则编译期会给出告警,并在运行时崩溃

@Link name: string | undefined; ----支持联合类型

@Watch监听的写法

js 复制代码
 @Link @Watch('onChangeSonToP') SonToParentText: string;
  onChangeSonToP() {
    console.info('111')
  }

@Provide @Consume 双向同步

js 复制代码
 // 提供
 @Provide parentArg: string = ' 父组件提供--provide'
 // 获取
  @Consume parentArg: string;

@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

注意事项

@ObjectLink装饰的变量不能被赋值,如果要使用赋值操作,请使用@Prop。

@ObjectLink装饰的变量和数据源的关系是双向同步

@Observed装饰的类,如果其属性为非简单类型,比如class、Object或者数组,那么这些属性也需要被@Observed装饰,否则将观察不到这些属性的变化。

定义

从父组件初始化

必须指定。

初始化@ObjectLink装饰的变量必须同时满足以下场景:

  • 类型必须是@Observed装饰的class。
  • 初始化的数值需要是数组项,或者class的属性。
示例代码
js 复制代码
@Observed
class Book {
  name: string;

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

@Observed
class Bag {
  book: Book;

  constructor(book: Book) {
    this.book = book;
  }
}

@Component
struct BookCard {
  @ObjectLink book: Book;

  build() {
    Column() {
      Text(`BookCard: ${this.book.name}`) // 可以观察到name的变化
        .width(320)
        .margin(10)
        .textAlign(TextAlign.Center)

      Button('change book.name')
        .width(320)
        .margin(10)
        .onClick(() => {
          this.book.name = 'C++';
        })
    }
  }
}

@Entry
@Component
struct Index {
  @State bag: Bag = new Bag(new Book('JS'));

  build() {
    Column() {
      Text(`Index: ${this.bag.book.name}`) // 无法观察到name的变化
        .width(320)
        .margin(10)
        .textAlign(TextAlign.Center)

      Button('change bag.book.name')
        .width(320)
        .margin(10)
        .onClick(() => {
          this.bag.book.name = 'TS';
        })

      BookCard({ book: this.bag.book })
    }
  }
}

@Track

@Track是class对象的属性装饰器。当一个class对象是状态变量时,@Track装饰的属性发生变化,只会触发该属性关联的UI更新;如果class类中使用了@Track装饰器,则未被@Track装饰器装饰的属性不能在UI中使用,如果使用,会发生运行时报错。

js 复制代码
class TrackLock {
  @Track name: string;
  @Track age: string;

  constructor(name: string, age: string) {
    this.name = name
    this.age = age
  }
}

class TrackNoLock {
  name1: string;
  age1: string

  constructor(name1: string, age1: string) {
    this.name1 = name1
    this.age1 = age1
  }
}

@Component
export struct TrackTest {
  @State trackLock: TrackLock = new TrackLock('小明', '15')
  @State trackNoLock: TrackNoLock = new TrackNoLock('小明1', '18')

  isRender(index: number) {
    console.info(`Text ${index} is rendered`);
    return 50;
  }

  build() {
    Column() {
      Text('trackLock-测试')
      Text(this.trackLock.name)
        .fontSize(this.isRender(1))
      Text(this.trackLock.age)
        .fontSize(this.isRender(2))
      Text('trackNoLock-测试')
      Text(this.trackNoLock.name1)
        .fontSize(this.isRender(3))
      Text(this.trackNoLock.age1)
        .fontSize(this.isRender(4))
      Button('测试').onClick((event: ClickEvent) => {
        this.trackLock.name = '11'
        // 输入  Text 1 is rendered

      })
      Button('change logNotTrack.str1')
        .onClick(() => {
          this.trackNoLock.name1 = '再见';
          // 输出
          Text 3 is rendered
          Text 4 is rendered
        })
    }
  }
}

@Builder装饰器:自定义构建函数

arkUI提供轻量的UI元素复用机制@Builder,其内部UI结构固定,仅与使用方进行数据传递。开发者可将重复使用的UI元素抽象成函数,在build函数中调用。

@Builder装饰的函数也称为"自定义构建函数"。

封装可复用的UI结构

@LocalBuilder维持组件关系

注意事项

  • @LocalBuilder只能在所属组件内声明,不允许全局声明。

  • @LocalBuilder不能与内置装饰器或自定义装饰器一起使用。

  • 在自定义组件中,@LocalBuilder不能用来装饰静态函数。

== 允许在自定义组件内定义一个或多个@LocalBuilder函数,该函数被认为是该组件的私有、特殊类型的成员函数。==

@LocalBuilder和局部@Builder使用区别

跨组件传递局部@Builder函数时,会使用.bind(this)更改函数上下文,但这可能会导致组件的父子关系与状态管理的父子关系不一致。而@LocalBuilder无论是否使用.bind(this),都不会改变组件的父子关系,即@LocalBuilder中定义组件所属的父组件是确定的,无法被改变。

js 复制代码
//----------------------------- 传递 父组件 Parent
  label: string = 'Parent';
  @LocalBuilder
  builderChild() {
    Text('Builder-child---' + this.label)
  }
// ------------------
//---------------------------- 使用 在父组件中使用
   Row() {
      Text('父')
      this.builderChild()
    }
    Child({ customBuilderParams: this.builderChild })
//-------------------------- 子组件接收 Child
  label: string = 'Child';
  @BuilderParam customBuilderParams: () => void

@BuilderParam装饰器:引用@Builder函数

@BuilderParam用于装饰指向@Builder方法的变量,通过调用@BuilderParam为组件增加特定功能。

如果不这样的话会导致所有自定义组件都增加此实例方法。

@BuilderParam装饰的方法只能被自定义构建函数(@Builder装饰的方法)初始化。

@Styles支持全局和局部 不支持传参数

@Extend仅支持全局定义 支持传递参数

@Require校验构造参数

当Child组件内使用@Require装饰器和@Prop、@State、@Provide、@BuilderParam、@Param和普通变量(无状态装饰器修饰的变量)结合使用时,父组件Index在构造Child时必须传参,否则编译不通过。

相关推荐
光芒Shine4 小时前
【HarmonyOS-App发布】
harmonyos
m0_6855350813 小时前
光线追击算法
华为·zemax·光学·光学设计·光学工程
爱笑的眼睛1115 小时前
HarmonyOS分布式Kit深度解析:实现高效跨设备协同
华为·harmonyos
坚果的博客19 小时前
鸿蒙PC使用aarch64的原因分析
华为·harmonyos
数字化顾问20 小时前
(114页PPT)华为FusionCloud私有云最佳实践RegionTypeII(附下载方式)
运维·服务器·华为
HarmonyOS_SDK20 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 — Push Kit
harmonyos
猫林老师21 小时前
Flutter for HarmonyOS开发指南(二):混合开发架构与通信机制
flutter·架构·harmonyos
特立独行的猫a1 天前
HarmonyOS黑马云音乐项目增加网络听歌功能(一、轮播图的实现)
网络·华为·harmonyos·开源项目·黑马云音乐
金鸿客1 天前
鸿蒙线性布局Row和Column详解
harmonyos