您的位置:首页 > 汽车 > 时评 > 设计师网红_三亚发布紧急通知_百度关键词搜索推广_杭州seo哪家好

设计师网红_三亚发布紧急通知_百度关键词搜索推广_杭州seo哪家好

2025/1/8 12:19:31 来源:https://blog.csdn.net/ChinaDragon10/article/details/144877580  浏览:    关键词:设计师网红_三亚发布紧急通知_百度关键词搜索推广_杭州seo哪家好
设计师网红_三亚发布紧急通知_百度关键词搜索推广_杭州seo哪家好

@Reusable装饰器装饰任意自定义组件时,表示该自定义组件可以复用。

说明
从API version 10开始,对@Reusable进行支持,支持在ArkTS中使用。

一、概述

@Reusable适用自定义组件,与@Component结合使用,标记为@Reusable的自定义组件从组件树上被移除时,组件和其对应的JSView对象都会被放入复用缓存中,后续创建新自定义组件节点时,会复用缓存区中的节点,节约组件重新创建的时间。

二、限制条件

@Reusable装饰器仅用于自定义组件。

// 编译报错,仅用于自定义组件@Reusable@Builderfunction buildCreativeLoadingDialog(closedClick: () => void) {Crash()}

ComponentContent不支持传入@Reusable装饰器装饰的自定义组件。

示例效果图

在这里插入图片描述

示例代码

import { ComponentContent } from "@kit.ArkUI"// @Reusable装饰器仅用于自定义组件。
// 编译报错,仅用于自定义组件
// @Reusable // 注释掉编译不报错
@Builder
function buildCreativeLoadingDialog(closedClick: () => void) {Crash()
}// 如果注释掉就可以正常弹出弹窗,如果加上@Reusable就直接crash
@Reusable
@Component
export struct Crash {build() {Column() {Text("Crash").fontSize(12).lineHeight(18).fontColor(Color.Blue).margin({left: 6})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}
}@Builder
function buildCreativeLoadingDialog2(closedClick: () => void) {Crash2()
}@Component
export struct Crash2 {build() {Column() {Text("Crash2 弹框提示, 没有使用@Reusable装饰器").fontSize(20).lineHeight(18).fontColor(Color.Blue).margin({left: 6,top: 100}).padding(26).backgroundColor(Color.White).borderRadius(8).width(300).height(200)}.width('100%').height('100%').justifyContent(FlexAlign.Start)}
}@Entry
@Component
struct TestReusable {@State message: string = '@Reusable装饰器:组件复用';private uicontext = this.getUIContext()build() {RelativeContainer() {Text(this.message).id('Index').fontSize(20).fontWeight(FontWeight.Bold).alignRules({center: { anchor: '__container__', align: VerticalAlign.Center },middle: { anchor: '__container__', align: HorizontalAlign.Center }}).onClick(() => {// ComponentContent底层是buildNode,buildNode不支持传入@Reusable注解的自定义组件let contentNode = new ComponentContent(this.uicontext, wrapBuilder(buildCreativeLoadingDialog), () => {});this.uicontext.getPromptAction().openCustomDialog(contentNode);// 传入不使用@Reusable注解的自定义组件// let contentNode2 = new ComponentContent(this.uicontext, wrapBuilder(buildCreativeLoadingDialog2), () => {// });// this.uicontext.getPromptAction().openCustomDialog(contentNode2);})}.height('100%').width('100%')}
}

传入不使用@Reusable注解的自定义组件效果图

在这里插入图片描述

@Reusable装饰器不支持嵌套使用。

效果图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

ReusableMessage.ets代码

export class ReusableMessage {value: string | undefinedconstructor(value: string) {this.value = value}
}

TestReusable2.ets代码

import { ReusableMessage } from "./ReusableMessage"@Entry
@Component
struct TestReusable2 {@State switch: boolean = true;@State childswitch: boolean = false;build() {Column() {Button('click').fontSize(30).fontWeight(FontWeight.Bold).onClick(() => {this.switch = !this.switch;})if (this.switch) {// 父自定义组件已经添加@Reusable(出于描述方便,以下子组件代指自定义组件,父组件代指父自定义组件)Parent({ message: new ReusableMessage('Parent') }).reuseId('Parent')}}.height("100%").width('100%')}
}@Reusable
@Component
struct Parent {@State message: ReusableMessage = new ReusableMessage('AboutToReuse');@State switchchild: boolean = true;aboutToRecycle(): void {console.info("aboutToRecycle===Parent ====Child==");}aboutToReuse(params: Record<string, ESObject>) {this.message = params.message as ReusableMessage;console.info("aboutToReuse==Parent====Child==" + this.message.value);}build() {Column() {Button('click child').fontSize(30).fontWeight(FontWeight.Bold).onClick(() => {this.switchchild = !this.switchchild;})// 子自定义组件if (this.switchchild) {// 父自定义组件已经添加@ReusableHasReusableChild({ message: new ReusableMessage('From ChildReuse') });}Text(this.message.value).fontSize(30)}.borderWidth(1).height(100)}
}// 可复用的自定义组件的子树中存在可复用的自定义组件,如果子组件标记@Reuable,会导致同一颗子树下复用率变低,因此不建议子组件加上@Reusable
@Reusable
@Component
export struct HasReusableChild {@State message: ReusableMessage = new ReusableMessage('AboutToReuse');// 子组件有@Reusable,单独刷新子组件,执行了子组件的aboutToReuse,父组件是不复用的aboutToAppear(): void {console.info("aboutToAppear=== HasReusableChild ====Child==");}aboutToDisappear(): void {console.info("aboutToDisappear=== HasReusableChild ====Child==");}aboutToRecycle(): void {console.info("aboutToRecycle=== HasReusableChild ====Child==");}// 正常复用,父组件刷新,引发子组件aboutToReuse方法的执行aboutToReuse(params: Record<string, ESObject>) {this.message = params.message as ReusableMessage;console.info("aboutToReuse== HasReusableChild ====Child==" + this.message.value);}build() {Column() {Text(this.message.value).fontSize(12).lineHeight(18).fontColor(Color.Blue).margin({left: 6})}.width('100%').height('100%').justifyContent(FlexAlign.Center)}
}

三、使用场景

  • 列表滚动:当应用需要展示大量数据的列表,并且用户进行滚动操作时,频繁创建和销毁列表项的视图可能导致卡顿和性能问题。在这种情况下,使用列表组件的组件复用机制可以重用已经创建的列表项视图,提高滚动的流畅度。
  • 动态布局更新:如果应用中的界面需要频繁地进行布局更新,例如根据用户的操作或数据变化动态改变视图结构和样式,重复创建和销毁视图可能导致频繁的布局计算,影响帧率。在这种情况下,使用组件复用可以避免不必要的视图创建和布局计算,提高性能。
  • 频繁创建和销毁数据项的视图场景下。使用组件复用可以重用已创建的视图,只更新数据的内容,减少视图的创建和销毁,能有效提高性能。

四、使用场景举例

4.1 动态布局更新
  • 示例代码将Child自定义组件标记为复用组件,通过Button点击更新Child,触发Child复用;
  • @Reusable:自定义组件被@Reusable装饰器修饰,即表示其具备组件复用的能力;
  • aboutToReuse:当一个可复用的自定义组件从复用缓存中重新加入到节点树时,触发aboutToReuse生命周期回调,并将组件的构造参数传递给aboutToReuse。

TestReusable3.ets代码

import { ReusableMessage } from "./ReusableMessage"@Entry
@Component
struct TestReusable3 {@State switch: boolean = true;build() {Column() {Button('Hello').fontSize(30).fontWeight(FontWeight.Bold).onClick(() => {this.switch = !this.switch;})if (this.switch) {Child({ message: new ReusableMessage('Child') })// 如果只有一个复用的组件,可以不用设置reuseId.reuseId('Child')}}.height("100%").width('100%')}
}@Reusable
@Component
struct Child {@State message: ReusableMessage = new ReusableMessage('AboutToReuse');aboutToReuse(params: Record<string, ESObject>) {console.info("Recycle ====Child==");this.message = params.message as ReusableMessage;}build() {Column() {Text(this.message.value).fontSize(30)}.borderWidth(1).height(100)}
}

效果图

在这里插入图片描述

4.2 列表滚动配合LazyForEach使用
  • 示例代码将CardView自定义组件标记为复用组件,List上下滑动,触发CardView复用;
  • @Reusable:自定义组件被@Reusable装饰器修饰,即表示其具备组件复用的能力;
  • 变量item的被@State修饰,才能更新,非@State修饰变量存在无法更新问题。

TestReusable4.ets代码

class MyDataSource implements IDataSource {private dataArray: string[] =["示例代码将CardView自定义组件标记为复用组件,List上下滑动,触发CardView复用;","自定义组件被@Reusable装饰器修饰,即表示其具备组件复用的能力;","变量item的被@State修饰,才能更新,非@State修饰变量存在无法更新问题。"];private listener: DataChangeListener | undefined;public totalCount(): number {return this.dataArray.length;}public getData(index: number): string {return this.dataArray[index];}public pushData(data: string): void {this.dataArray.push(data);}public reloadListener(): void {this.listener?.onDataReloaded();}public registerDataChangeListener(listener: DataChangeListener): void {this.listener = listener;}public unregisterDataChangeListener(listener: DataChangeListener): void {this.listener = undefined;}
}@Entry
@Component
struct TestReusable4 {private data: MyDataSource = new MyDataSource();build() {Column() {List() {LazyForEach(this.data, (item: string) => {ListItem() {CardView({ item: item })}}, (item: string) => item)}}}
}// 复用组件
@Reusable
@Component
export struct CardView {@State item: string = '';aboutToReuse(params: Record<string, Object>): void {this.item = params.item as string;}build() {Column({ space: 10 }) {Text(this.item).fontSize(20)}.borderWidth(1).height(100)}
}

效果图

在这里插入图片描述

4.3 if使用场景
  • 示例代码将OneMoment自定义组件标记为复用组件,List上下滑动,触发OneMoment复用;
  • 可以使用reuseId为复用组件分配复用组,相同reuseId的组件会在同一个复用组中复用,如果只有一个复用的组件,可以不用设置reuseId;
  • 通过reuseId来标识需要复用的组件,省去重复执行if的删除重创逻辑,提高组件复用的效率和性能。
@Entry
@Component
struct withoutReuseId {aboutToAppear(): void {getFriendMomentFromRawfile();}build() {Column() {TopBar()List({ space: ListConstants.LIST_SPACE }) {LazyForEach(momentData, (moment: FriendMoment) => {ListItem() {OneMoment({moment: moment})// 使用reuseId进行组件复用的控制.reuseId((moment.image !== '') ? 'withImage' : 'noImage')}}, (moment: FriendMoment) => moment.id)}.cachedCount(Constants.CACHED_COUNT)}}
}@Reusable
@Component
export struct OneMoment {@Prop moment: FriendMoment;build() {Column() {...Text(this.moment.text)if (this.moment.image !== '') {Flex({ wrap: FlexWrap.Wrap }) {Image($r(this.moment.image))Image($r(this.moment.image))Image($r(this.moment.image))Image($r(this.moment.image))}}...}}
}
4.4 Foreach使用场景
  • 示例点击update,数据刷新成功,但是滑动列表,组件复用无法使用,Foreach的折叠展开属性的原因;
  • 点击clear,再次update,复用成功;符合一帧内重复创建多个已被销毁的自定义组件;
// xxx.ets
class MyDataSource implements IDataSource {private dataArray: string[] = [];public totalCount(): number {return this.dataArray.length;}public getData(index: number): string {return this.dataArray[index];}public pushData(data: string): void {this.dataArray.push(data);}public registerDataChangeListener(listener: DataChangeListener): void {}public unregisterDataChangeListener(listener: DataChangeListener): void {}
}@Entry
@Component
struct Index {private data: MyDataSource = new MyDataSource();private data02: MyDataSource = new MyDataSource();@State isShow: boolean = true;@State dataSource: ListItemObject[] = [];aboutToAppear() {for (let i = 0; i < 100; i++) {this.data.pushData(i.toString())}for (let i = 30; i < 80; i++) {this.data02.pushData(i.toString())}}build() {Column() {Row() {Button('clear').onClick(() => {for (let i = 1; i < 50; i++) {let obj = new ListItemObject();obj.id = i;obj.uuid = Math.random().toString();obj.isExpand = false;this.dataSource.pop();}}).height(40)Button('update').onClick(() => {for (let i = 1; i < 50; i++) {let obj = new ListItemObject();obj.id = i;obj.uuid = Math.random().toString();obj.isExpand = falsethis.dataSource.push(obj);}}).height(40)}List({ space: 10 }) {ForEach(this.dataSource, (item: ListItemObject) => {ListItem() {ListItemView({obj: item})}}, (item: ListItemObject) => {return item.uuid.toString()})}.cachedCount(0).width('100%').height('100%')}}
}@Reusable
@Component
struct ListItemView {@ObjectLink obj: ListItemObject;@State item: string = '';aboutToAppear(): void {// 点击 update,首次进入,上下滑动,由于Foreach折叠展开属性,无法复用console.log("=====abouTo===Appear=====ListItemView==创建了==" + this.item)}aboutToReuse(params: ESObject) {this.item = params.item;// 点击 clear,再次update,复用成功// 符合一帧内重复创建多个已被销毁的自定义组件console.log("=====aboutTo===Reuse====ListItemView==复用了==" + this.item)}build() {Column({ space: 10 }) {Text(`${this.obj.id}.标题`).fontSize(16).fontColor('#000000').padding({top: 20,bottom: 20,})if (this.obj.isExpand) {Text('').fontSize(14).fontColor('#999999')}}.width('100%').borderRadius(10).backgroundColor(Color.White).padding(15).onClick(() => {this.obj.isExpand = !this.obj.isExpand;})}
}@Observed
class ListItemObject {uuid: string = "";id: number = 0;isExpand: boolean = false;
}
4.5 Grid使用场景
  • 示例中使用@Reusable装饰器修饰GridItem中的自定义组件ReusableChildComponent,即表示其具备组件复用的能力;
  • 使用aboutToReuse是为了让Grid在滑动时从复用缓存中加入到组件树之前触发,用于更新组件的状态变量以展示正确的内容;
  • 需要注意的是无需在aboutToReuse中对@Link、@StorageLink、@ObjectLink、@Consume等自动更新值的状态变量进行更新,可能触发不必要的组件刷新。
// MyDataSource类实现IDataSource接口
class MyDataSource implements IDataSource {private dataArray: number[] = [];public pushData(data: number): void {this.dataArray.push(data);}// 数据源的数据总量public totalCount(): number {return this.dataArray.length;}// 返回指定索引位置的数据public getData(index: number): number {return this.dataArray[index];}registerDataChangeListener(listener: DataChangeListener): void {}unregisterDataChangeListener(listener: DataChangeListener): void {}
}@Entry
@Component
struct MyComponent {// 数据源private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 1; i < 1000; i++) {this.data.pushData(i);}}build() {Column({ space: 5 }) {Grid() {LazyForEach(this.data, (item: number) => {GridItem() {// 使用可复用自定义组件ReusableChildComponent({ item: item })}}, (item: string) => item)}.cachedCount(2) // 设置GridItem的缓存数量.columnsTemplate('1fr 1fr 1fr').columnsGap(10).rowsGap(10).margin(10).height(500).backgroundColor(0xFAEEE0)}}
}// 自定义组件被@Reusable装饰器修饰,即标志其具备组件复用的能力
@Reusable
@Component
struct ReusableChildComponent {@State item: number = 0;// aboutToReuse从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容// aboutToReuse参数类型已不支持any,这里使用Record指定明确的数据类型。Record用于构造一个对象类型,其属性键为Keys,属性值为TypeaboutToReuse(params: Record<string, number>) {this.item = params.item;}build() {Column() {Image($r('app.media.icon')).objectFit(ImageFit.Fill).layoutWeight(1)Text(`图片${this.item}`).fontSize(16).textAlign(TextAlign.Center)}.width('100%').height(120).backgroundColor(0xF9CF93)}
}
4.6 WaterFlow使用场景
  • WaterFlow滑动场景存在FlowItem及其子组件的频繁创建和销毁,可以将FlowItem中的组件封装成自定义组件,并使用@Reusable装饰器修饰,使其具备组件复用能力;
  build() {Column({ space: 2 }) {WaterFlow() {LazyForEach(this.datasource, (item: number) => {FlowItem() {// 使用可复用自定义组件  ReusableFlowItem({ item: item })}.onAppear(() => {// 即将触底时提前增加数据  if (item + 20 == this.datasource.totalCount()) {for (let i = 0; i < 100; i++) {this.datasource.AddLastItem()}}}).width('100%').height(this.itemHeightArray[item % 100]).backgroundColor(this.colors[item % 5])}, (item: string) => item)}.columnsTemplate("1fr 1fr").columnsGap(10).rowsGap(5).backgroundColor(0xFAEEE0).width('100%').height('80%')}}
@Reusable
@Component
struct ReusableFlowItem {@State item: number = 0;// 从复用缓存中加入到组件树之前调用,可在此处更新组件的状态变量以展示正确的内容aboutToReuse(params) {this.item = params.item;}build() {Column() {Text("N" + this.item).fontSize(12).height('16')Image('res/waterFlowTest (' + this.item % 5 + ').jpg').objectFit(ImageFit.Fill).width('100%').layoutWeight(1)}}
}
4.7 多种条目类型使用场景

标准型

  • 复用组件之间布局完全相同;
  • 示例同列表滚动中描述;

有限变化型

  • 复用组件之间有不同,但是类型有限;
  • 示例为复用组件显式设置两个reuseId与使用两个自定义组件进行复用;
class MyDataSource implements IDataSource {...
}@Entry
@Component
struct Index {private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 0; i < 1000; i++) {this.data.pushData(i);}}build() {Column() {List({ space: 10 }) {LazyForEach(this.data, (item: number) => {ListItem() {ReusableComponent({ item: item }).reuseId(item % 2 === 0 ? 'ReusableComponentOne' : 'ReusableComponentTwo')}.backgroundColor(Color.Orange).width('100%')}, (item: number) => item.toString())}.cachedCount(2)}}
}@Reusable
@Component
struct ReusableComponent {@State item: number = 0;aboutToReuse(params: ESObject) {this.item = params.item;}build() {Column() {if (this.item % 2 === 0) {Text(`Item ${this.item} ReusableComponentOne`).fontSize(20).margin({ left: 10 })} else {Text(`Item ${this.item} ReusableComponentTwo`).fontSize(20).margin({ left: 10 })}}.margin({ left: 10, right: 10 })}
}

组合型

  • 复用组件之间有不同,情况非常多,但是拥有共同的子组件;
    示例按照组合型的组件复用方式,将上述示例中的三种复用组件转变为Builder函数后,内部共同的子组件就处于同一个父组件MyComponent下;
  • 对这些子组件使用组件复用时,它们的缓存池也会在父组件上共享,节省组件创建时的消耗。
class MyDataSource implements IDataSource {...
}@Entry
@Component
struct MyComponent {private data: MyDataSource = new MyDataSource();aboutToAppear() {for (let i = 0; i < 1000; i++) {this.data.pushData(i.toString())}}@BuilderitemBuilderOne(item: string) {Column() {ChildComponentA({ item: item })ChildComponentB({ item: item })ChildComponentC({ item: item })}}@BuilderitemBuilderTwo(item: string) {Column() {ChildComponentA({ item: item })ChildComponentC({ item: item })ChildComponentD({ item: item })}}@BuilderitemBuilderThree(item: string) {Column() {ChildComponentA({ item: item })ChildComponentB({ item: item })ChildComponentD({ item: item })}}build() {List({ space: 40 }) {LazyForEach(this.data, (item: string, index: number) => {ListItem() {if (index % 3 === 0) {this.itemBuilderOne(item)} else if (index % 5 === 0) {this.itemBuilderTwo(item)} else {this.itemBuilderThree(item)}}.backgroundColor('#cccccc').width('100%').onAppear(() => {console.log(`ListItem ${index} onAppear`);})}, (item: number) => item.toString())}.width('100%').height('100%').cachedCount(0)}
}@Reusable
@Component
struct ChildComponentA {@State item: string = '';aboutToReuse(params: ESObject) {console.log(`ChildComponentA ${params.item} Reuse ${this.item}`);this.item = params.item;}aboutToRecycle(): void {console.log(`ChildComponentA ${this.item} Recycle`);}build() {Column() {Text(`Item ${this.item} Child Component A`).fontSize(20).margin({ left: 10 }).fontColor(Color.Blue)Grid() {ForEach((new Array(20)).fill(''), (item: string,index: number) => {GridItem() {Image($r('app.media.startIcon')).height(20)}})}.columnsTemplate('1fr 1fr 1fr 1fr 1fr').rowsTemplate('1fr 1fr 1fr 1fr').columnsGap(10).width('90%').height(160)}.margin({ left: 10, right: 10 }).backgroundColor(0xFAEEE0)}
}@Reusable
@Component
struct ChildComponentB {@State item: string = '';aboutToReuse(params: ESObject) {this.item = params.item;}build() {Row() {Text(`Item ${this.item} Child Component B`).fontSize(20).margin({ left: 10 }).fontColor(Color.Red)}.margin({ left: 10, right: 10 })}
}@Reusable
@Component
struct ChildComponentC {@State item: string = '';aboutToReuse(params: ESObject) {this.item = params.item;}build() {Row() {Text(`Item ${this.item} Child Component C`).fontSize(20).margin({ left: 10 }).fontColor(Color.Green)}.margin({ left: 10, right: 10 })}
}@Reusable
@Component
struct ChildComponentD {@State item: string = '';aboutToReuse(params: ESObject) {this.item = params.item;}build() {Row() {Text(`Item ${this.item} Child Component D`).fontSize(20).margin({ left: 10 }).fontColor(Color.Orange)}.margin({ left: 10, right: 10 })}
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com