【HarmonyOS】@Observed和@ObjectLink嵌套对象属性更改UI不刷新问题
一、问题背景
使用了@Observed和@ObjectLink,修改嵌套对象的属性,UI还是不刷新,常见的问题有以下三种形式:
1.多级嵌套,嵌套对象的类并没有添加@Observed进行监听
2.多级嵌套,嵌套对象的View组件没有抽离出来,添加@ObjectLink进行该级对象的监听绑定
3.嵌套对象,并没有new出来创建,直接赋值没有创建对象的过程,无法激活Observed监听
二、代码举例
以代码示例举例:
1.创建了接口TestInfoInterFace ,父类TestInfo,嵌套类TestItem 。
interface TestInfoInterFace {
name: string;
items: TestItem[];
}
class TestItem {
content: string = "";
isClicked: boolean = false;
}
class TestInfo {
name: string;
items: TestItem[];
constructor(name: string, items: TestItem[]) {
this.name = name;
this.items = items;
}
}
2.添加测试数据,渲染列表,单元格数据基本类型结构为TestInfo。
TestPage {
mTestDataArr: TestInfo[] = [
new TestInfo('测试数据1', [{
content: '单元数据1',
isClicked: false
}, {
content: '单元数据1',
isClicked: false
}]),
new TestInfo('测试数据2', [{
content: '单元数据1',
isClicked: false
}, {
content: '单元数据1',
isClicked: false
}]),
new TestInfo('测试数据3', [{
content: '单元数据1',
isClicked: false
}, {
content: '单元数据1',
isClicked: false
}]),
]
build() {
Column() {
ForEach(this.mTestDataArr, (item: TestInfoInterFace) => {
ChildView({
mTestInfo: item
})
})
}
.width('100%')
.height('100%')
}
}
struct
3.抽离嵌套组件ChildView ,绑定双向监听。
export struct ChildView {
private TAG: string = "TestPage";
mTestInfo: TestInfo
build() {
Column() {
Text(this.mTestInfo.name)
.backgroundColor(Color.Red)
.fontSize(px2fp(52))
ForEach(this.mTestInfo.items, (tempInfo: TestItem) => {
Text(tempInfo.content)
.fontSize(px2fp(52))
.backgroundColor(tempInfo.isClicked ? Color.Blue : Color.Yellow)
.onClick(() => {
tempInfo.isClicked = !tempInfo.isClicked
console.log(this.TAG, JSON.stringify(tempInfo))
})
})
Divider()
}
}
}
渲染界面后的效果为:
此时我们点击单元数据1或者2,去修改isClicked选中状态,并不会刷新UI,整个代码有以上总结的三个问题:
1.TestItem 多级嵌套,嵌套对象的类并没有添加@Observed进行监听
2.ChildView 多级嵌套了一个层级,直接就进行了循环渲染,其嵌套对象的View组件没有抽离出来,添加@ObjectLink进行该级对象的监听绑定
3.mTestDataArr嵌套对象中的TestItem并没有new出来创建,是通过花括号直接赋值没有创建对象的过程,无法激活Observed监听
三、完整DEMO示例:
interface TestInfoInterFace {
name: string;
items: TestItem[];
}
// TODO 问题1:多层级时,需要逐个层级进行类监听
class TestItem {
content: string = "";
isClicked: boolean = false;
constructor(content: string, isClicked: boolean) {
this.content = content;
this.isClicked = isClicked;
}
}
class TestInfo {
name: string;
items: TestItem[];
constructor(name: string, items: TestItem[]) {
this.name = name;
this.items = items;
}
}
struct TestPage {
// TODO 问题3 每个被设置Observed的对象,需要new出来创建,才能激活监听,花括号的形式赋值,并不会激活监听。
mTestDataArr: TestInfo[] = [
new TestInfo('测试数据1', [new TestItem('单元数据1', false), new TestItem('单元数据2', false)]),
new TestInfo('测试数据2', [new TestItem('单元数据1', false), new TestItem('单元数据2', false)]),
new TestInfo('测试数据3', [new TestItem('单元数据1', false), new TestItem('单元数据2', false)]),
// new TestInfo('测试数据1', [{
// content: '单元数据1',
// isClicked: false
// }, {
// content: '单元数据1',
// isClicked: false
// }]),
// new TestInfo('测试数据2', [{
// content: '单元数据1',
// isClicked: false
// }, {
// content: '单元数据1',
// isClicked: false
// }]),
// new TestInfo('测试数据3', [{
// content: '单元数据1',
// isClicked: false
// }, {
// content: '单元数据1',
// isClicked: false
// }]),
]
build() {
Column() {
ForEach(this.mTestDataArr, (item: TestInfoInterFace) => {
ChildView({
mTestInfo: item
})
})
}
.width('100%')
.height('100%')
}
}
export struct ChildView {
private TAG: string = "TestPage";
mTestInfo: TestInfo
build() {
Column() {
Text(this.mTestInfo.name)
.backgroundColor(Color.Red)
.fontSize(px2fp(52))
// TODO 多层级时,需要逐个层级进行剥离,创建子组件和绑定双向监听。
// ForEach(this.mTestInfo.items, (tempInfo: TestItem) => {
// Text(tempInfo.content)
// .fontSize(px2fp(52))
// .backgroundColor(tempInfo.isClicked ? Color.Blue : Color.Yellow)
// .onClick(() => {
// tempInfo.isClicked = !tempInfo.isClicked
// console.log(this.TAG, JSON.stringify(tempInfo))
// })
// })
ForEach(this.mTestInfo.items, (tempInfo: TestItem) => {
ItemView({
mItem: tempInfo
}).margin({
top: px2vp(100)
})
})
Divider()
}
}
}
export struct ItemView {
private TAG: string = "TestPage";
mItem: TestItem
build() {
Text(this.mItem.content)
.fontSize(px2fp(52))
.backgroundColor(this.mItem.isClicked ? Color.Blue : Color.Yellow)
.onClick(() => {
this.mItem.isClicked = !this.mItem.isClicked
console.log(this.TAG, JSON.stringify(this.mItem))
})
}
}