目录
1、观察变化
2、框架行为
3、简单类型和类对象类型的@Link
4、数组类型的@Link
子组件中被@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定,父组件中数据的变化会反映到子组件中,同样子组件中数据的变化也会反映到父组件中。
- @Link装饰器不能在@Entry装饰的自定义组件中使用。
- @Link装饰器修饰的变量禁止本地初始化(只能从父组件初始化)。
- @Link装饰器修饰的变量不支持从组件外访问,它是组件私有的,只能在所属组件内访问。
@Link装饰的变量和其所属的自定义组件共享生命周期。
为了了解@Link变量初始化和更新机制,有必要先了解父组件和拥有@Link变量的子组件的关系,初始渲染和双向更新的流程(以父组件为@State为例)。
class GreenButtonState {
width: number = 0;
constructor(width: number) {
this.width = width;
}
}
@Component
struct GreenButton {
@Link greenButtonState: GreenButtonState;
build() {
Button('Green Button')
.width(this.greenButtonState.width)
.height(40)
.backgroundColor('#64bb5c')
.fontColor('#FFFFFF,90%')
.onClick(() => {
if (this.greenButtonState.width < 700) {
// 更新class的属性,变化可以被观察到同步回父组件
this.greenButtonState.width += 60;
} else {
// 更新class,变化可以被观察到同步回父组件
this.greenButtonState = new GreenButtonState(180);
}
})
}
}
@Component
struct YellowButton {
@Link yellowButtonState: number;
build() {
Button('Yellow Button')
.width(this.yellowButtonState)
.height(40)
.backgroundColor('#f7ce00')
.fontColor('#FFFFFF,90%')
.onClick(() => {
// 子组件的简单类型可以同步回父组件
this.yellowButtonState += 40.0;
})
}
}
@Entry
@Component
struct LinkDemo1Page {
@State greenButtonState: GreenButtonState = new GreenButtonState(180);
@State yellowButtonProp: number = 180;
build() {
Column() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
// 简单类型从父组件@State向子组件@Link数据同步
Button('Parent View: Set yellowButton')
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF,90%')
.onClick(() => {
this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 40 : 100;
})
// class类型从父组件@State向子组件@Link数据同步
Button('Parent View: Set GreenButton')
.width(312)
.height(40)
.margin(12)
.fontColor('#FFFFFF,90%')
.onClick(() => {
this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;
})
// class类型初始化@Link
GreenButton({ greenButtonState: $greenButtonState }).margin(12)
// 简单类型初始化@Link
YellowButton({ yellowButtonState: $yellowButtonProp }).margin(12)
}
}
}
}
该例演示了简单类型(number、string、boolean)和类对象类型在子组件中使用 @Link时与父组件之间的双向同步,无论是父组件还是子组件更新,相应的子组件和父组件都能正确得到更新。
@Component
struct LinkDemo2Child {
@Link items: number[];
build() {
Column() {
Button(`Button1: push`)
.margin(12)
.width(312)
.height(40)
.fontColor('#FFFFFF,90%')
.onClick(() => {
this.items.push(this.items.length + 1);
})
Button(`Button2: replace whole item`)
.margin(12)
.width(312)
.height(40)
.fontColor('#FFFFFF,90%')
.onClick(() => {
this.items = [100, 200, 300];
})
}
}
}
@Entry
@Component
struct LinkDemo2Page {
@State arr: number[] = [1, 2, 3];
build() {
Column() {
LinkDemo2Child({ items: $arr })
.margin(12)
ForEach(this.arr,
(item: void) => {
Button(`${item}`)
.margin(12)
.width(312)
.height(40)
.backgroundColor('#11a2a2a2')
.fontColor('#e6000000')
},
(item: ForEachInterface) => item.toString()
)
}
}
}
两个按钮位于子组件中,子组件中用@Link装饰了一个数组,在子组件中点击任意一个按钮,都会触发对数组的修改,该修改会同步到父组件中,父组件通过for each迭代展示了数组的内容。所以没点击一次push,会把一个数据添加到数组中,此时数组的变化反映到父组件中,父组件中依赖于数组的组件将会得到更新,于是遍历列表,UI上看到插入了一条数据。
子组件中点击replace,触发的数据更新及UI刷新流程与添加一条数据类似。