@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);
})
}
}
}
@Link
注意事项
- 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时必须传参,否则编译不通过。