@Computed装饰器:计算属性,在被计算的值变化的时候,只会计算一次。主要应用于解决UI多次重用该属性从而重复计算导致的性能问题。
说明
@Computed装饰器从API version 12开始支持。
当前状态管理(V2试用版)仍在逐步开发中,相关功能尚未成熟,建议开发者尝鲜试用。
概述
@Computed为方法装饰器,修饰getter方法。@Computed会检测被计算的属性变化,当被计算的属性变化时,@Computed只会被求解一次。
对于复杂的计算,@Computed会有性能收益。
装饰器说明
@Computed语法:
@Computed get varName(): T {
return value;
}
@Computed方法装饰器 | 说明 |
---|---|
支持类型 | getter访问器。 |
从父组件初始化 | 禁止。 |
可初始化子组件 | @Param |
被执行的时机 | @ComponentV2被初始化时,计算属性会被触发被计算。当被计算的值改变的时候,计算属性也会发生计算。 |
使用限制
- @Computed为方法装饰器修饰getter方法,在getter方法中,不能改变参与计算的属性。
@Computed
get fullName() {
this.lastName += 'a'; // error
return this.firstName + ' ' + this.lastName;
}
- @Computed不能和双向绑定!!连用,即@Computed修饰的是getter访问器,不会被子组件同步,也不能被赋值。
@Computed
get fullName() {
return this.firstName + ' ' + this.lastName;
}
Child({ fullName: this.fullName!! }) // error
- @Computed为状态管理V2提供的能力,只能在@ComponentV2和@ObservedV2中使用。
- 多个@Computed一起使用时,警惕循环求解。
@Local a : number = 1;
@Computed
get b() {
return this.a + ' ' + this.c; // error: b -> c -> b
}
@Computed
get c() {
return this.a + ' ' + this.b; // error: c -> b -> c
}
使用场景
当被计算的属性变化时,@Computed装饰的getter访问器只会被求解一次
- 在自定义组件中使用计算属性
- 点击第一个Button改变lastName,触发@Computed fullName重新计算。
- this.fullName被绑定在两个Text组件上,观察fullName日志,可以发现,计算只发生了一次。
- 对于前两个Text组件,this.lastName + ' '+ this.firstName这段逻辑被求解了两次。
- 如果UI中有多处需要使用this.lastName + ' '+ this.firstName这段计算逻辑,可以使用计算属性,减少计算次数。
- 点击第二个Button,age自增,UI无变化。因为age非状态变量,只有被观察到的变化才会触发@Computed fullName重新计算。
@Entry
@ComponentV2
struct Index {
@Local firstName: string = 'Li';
@Local lastName: string = 'Hua';
age: number = 20; // cannot trigger Computed
@Computed
get fullName() {
console.info("---------Computed----------");
return this.firstName + ' ' + this.lastName + this.age;
}
build() {
Column() {
Text(this.lastName + ' ' + this.firstName)
Text(this.lastName + ' ' + this.firstName)
Divider()
Text(this.fullName)
Text(this.fullName)
Button('changed lastName').onClick(() => {
this.lastName += 'a';
})
Button('changed age').onClick(() => {
this.age++; // cannot trigger Computed
})
}
}
}
但是需要注意,计算属性本身是有性能开销的,实际应用开发中:
- 如果是上面这种简单计算,可以不使用计算属性。
- 如果在视图中只使用一次,也可以不使用计算属性,建议直接求解。
- 在@ObservedV2装饰的类中使用计算属性
- 点击Button改变lastName,触发@Computed fullName重新计算,且只被计算一次。
@ObservedV2
class Name {
@Trace firstName: string = 'Li';
@Trace lastName: string = 'Hua';
@Computed
get fullName() {
console.info('---------Computed----------');
return this.firstName + ' ' + this.lastName;
}
}
const name: Name = new Name();
@Entry
@ComponentV2
struct Index {
name1: Name = name;
build() {
Column() {
Text(this.name1.fullName)
Text(this.name1.fullName)
Button('changed lastName').onClick(() => {
this.name1.lastName += 'a';
})
}
}
}
@Computed装饰的属性可以被@Monitor监听变化
下面的例子展示了使用计算属性求解fahrenheit和kelvin。
- 点击“-”,celsius-- -> fahrenheit -> kelvin --> kelvin改变触发onKelvinMonitor。
- 点击“+”,celsius++ -> fahrenheit -> kelvin --> kelvin改变触发onKelvinMonitor。
@Entry
@ComponentV2
struct MyView {
@Local celsius: number = 20;
@Computed
get fahrenheit(): number {
return this.celsius * 9 / 5 + 32; // C -> F
}
@Computed
get kelvin(): number {
return (this.fahrenheit - 32) * 5 / 9 + 273.15; // F -> K
}
@Monitor("kelvin")
onKelvinMonitor(mon: IMonitor) {
console.log("kelvin changed from " + mon.value()?.before + " to " + mon.value()?.now);
}
build() {
Column({ space: 20 }) {
Row({ space: 20 }) {
Button('-')
.onClick(() => {
this.celsius--;
})
Text(`Celsius ${this.celsius.toFixed(1)}`).fontSize(50)
Button('+')
.onClick(() => {
this.celsius++;
})
}
Text(`Fahrenheit ${this.fahrenheit.toFixed(2)}`).fontSize(50)
Text(`Kelvin ${this.kelvin.toFixed(2)}`).fontSize(50)
}
.width('100%')
}
}
@Computed装饰的属性可以初始化@Param
下面的例子展示了@Computed初始@Param。
- 点击Button('-')和Button('+')改变商品数量,quantity是被@Trace修饰的,其改变时可以被观察到的。
- quantity的改变触发total和qualifiesForDiscount重新计算,计算商品总价和是否可以享有优惠。
- total和qualifiesForDiscount的改变触发子组件Child对应Text组件刷新。
@ObservedV2
class Article {
@Trace quantity: number = 0;
unitPrice: number = 0;
constructor(quantity: number, unitPrice: number) {
this.quantity = quantity;
this.unitPrice = unitPrice;
}
}
@Entry
@ComponentV2
struct Index {
@Local shoppingBasket: Article[] = [new Article(1, 20), new Article(5, 2)];
@Computed
get total(): number {
return this.shoppingBasket.reduce((acc: number, item: Article) => acc + (item.quantity * item.unitPrice), 0);
}
@Computed
get qualifiesForDiscount(): boolean {
return this.total >= 100;
}
build() {
Column() {
Text(`Shopping List: `).fontSize(30)
ForEach(this.shoppingBasket, (item: Article) => {
Row() {
Text(`unitPrice: ${item.unitPrice}`)
Button('-').onClick(() => {
if (item.quantity > 0) {
item.quantity--;
}
})
Text(`quantity: ${item.quantity}`)
Button('+').onClick(() => {
item.quantity++;
})
}
Divider()
})
Child({ total: this.total, qualifiesForDiscount: this.qualifiesForDiscount })
}.alignItems(HorizontalAlign.Start)
}
}
@ComponentV2
struct Child {
@Param total: number = 0;
@Param qualifiesForDiscount: boolean = false;
build() {
Row() {
Text(`Total: ${this.total} `).fontSize(30)
Text(`Discount: ${this.qualifiesForDiscount} `).fontSize(30)
}
}
}
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
点击领取→【纯血版鸿蒙全套最新学习资料】(安全链接,放心点击)希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取~限时开源!!
鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
HarmonyOS Next 最新全套视频教程
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
- ArkTS语言
- 安装DevEco Studio
- 运用你的第一个ArkTS应用
- ArkUI声明式UI开发
- .……
《鸿蒙开发进阶》
- Stage模型入门
- 网络管理
- 数据管理
- 电话服务
- 分布式应用开发
- 通知与窗口管理
- 多媒体技术
- 安全技能
- 任务管理
- WebGL
- 国际化开发
- 应用测试
- DFX面向未来设计
- 鸿蒙系统移植和裁剪定制
- ……
《鸿蒙进阶实战》
- ArkTS实践
- UIAbility应用
- 网络案例
- ……
大厂面试必问面试题
鸿蒙南向开发技术
鸿蒙APP开发必备
请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,华为鸿蒙不再兼容安卓,对程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,才能在这个变革的时代中立于不败之地。