前言
本文基于Api13
很多的场景下,父组件需要触发子组件中的某个方法,来实现一些特定的逻辑,但是ArkUI是声明式UI,不能直接调用子组件中的方法,那么怎么去实现这个功能呢?
举一个很常见的案例,通过调用子组件中的某个方法,实现子组件UI的更新,简单的代码如下,只有通过调用changeUI方法,才会触发UI的更新。
1@Component 2struct Child { 3 @State message: string = "我是子组件" 4 5 /** 6 *AUTHOR:AbnerMing 7 *INTRODUCE:子组件方法 8 */ 9 changeUI() { 10 this.message = "子组件UI更新了" 11 } 12 13 build() { 14 Text(this.message) 15 .width("100%") 16 .height(50) 17 .backgroundColor(Color.Pink) 18 .textAlign(TextAlign.Center) 19 } 20}
方式一:@Watch装饰器
如果你是用的V1版本装饰器,我们可以使用@Watch装饰器很轻松进行实现。
子组件定义@Watch装饰器
1@Component 2struct Child { 3 @State message: string = "我是子组件" 4 @Prop @Watch("changeUI") isChangeStatus: boolean = false 5 6 /** 7 *AUTHOR:AbnerMing 8 *INTRODUCE:子组件方法 9 */ 10 changeUI() { 11 this.message = "子组件UI更新了" 12 } 13 14 build() { 15 Text(this.message) 16 .width("100%") 17 .height(50) 18 .backgroundColor(Color.Pink) 19 .textAlign(TextAlign.Center) 20 } 21}
父组件调用
可通过子组件定义的isChangeStatus属性,不断的变化其值就可以了。
1@Entry 2 @Component 3 struct DemoPage { 4 @State isChangeStatus: boolean = false 5 6 build() { 7 Column() { 8 Child({ isChangeStatus: this.isChangeStatus }) 9 Button("点击") 10 .onClick(() => { 11 this.isChangeStatus = !this.isChangeStatus 12 }) 13 } 14 .height('100%') 15 .width('100%') 16 .justifyContent(FlexAlign.Center) 17 } 18 }
方式二:@Monitor装饰器
和方式一的实现方式是一致的,只不过,@Monitor装饰器是V2版本,也就是说,你使用的是V2版本装饰器的话,可以使用这个。
子组件定义@Monitor装饰器
1@ComponentV2 2struct Child { 3 @Local message: string = "我是子组件" 4 @Param isChangeStatus: boolean = false 5 6 /** 7 *AUTHOR:AbnerMing 8 *INTRODUCE:子组件方法 9 */ 10 @Monitor("isChangeStatus") 11 changeUI() { 12 this.message = "子组件UI更新了" 13 } 14 15 build() { 16 Text(this.message) 17 .width("100%") 18 .height(50) 19 .backgroundColor(Color.Pink) 20 .textAlign(TextAlign.Center) 21 } 22}
父组件调用
1@Entry 2@ComponentV2 3struct DemoPage { 4 @Local isChangeStatus: boolean = false 5 6 build() { 7 Column() { 8 Child({ isChangeStatus: this.isChangeStatus }) 9 Button("点击") 10 .onClick(() => { 11 this.isChangeStatus = !this.isChangeStatus 12 }) 13 } 14 .height('100%') 15 .width('100%') 16 .justifyContent(FlexAlign.Center) 17 } 18}
方式三:接口回调
定义回调函数
1class ChangeController { 2 change = () => {} 3}
子组件实现回调
1@Component 2struct Child { 3 @State message: string = "我是子组件" 4 changeController: ChangeController = new ChangeController() 5 6 aboutToAppear(): void { 7 if (this.changeController.change != undefined) { 8 this.changeController.change = () => { 9 this.changeUI() 10 } 11 } 12 } 13 14 /** 15 *AUTHOR:AbnerMing 16 *INTRODUCE:子组件方法 17 */ 18 changeUI() { 19 this.message = "子组件UI更新了" 20 } 21 22 build() { 23 Text(this.message) 24 .width("100%") 25 .height(50) 26 .backgroundColor(Color.Pink) 27 .textAlign(TextAlign.Center) 28 } 29}
父组件调用函数
1@Entry 2@Component 3struct DemoPage { 4 changeController: ChangeController = new ChangeController() 5 6 build() { 7 Column() { 8 Child({ changeController: this.changeController }) 9 Button("点击") 10 .onClick(() => { 11 this.changeController.change() 12 }) 13 } 14 .height('100%') 15 .width('100%') 16 .justifyContent(FlexAlign.Center) 17 } 18}
方式四:事件订阅EventHub
订阅事件
1@Component 2struct Child { 3 @State message: string = "我是子组件" 4 5 aboutToAppear(): void { 6 getContext().eventHub.on("changeUI", ()=>{ 7 this.changeUI() 8 }) 9 } 10 11 /** 12 *AUTHOR:AbnerMing 13 *INTRODUCE:子组件方法 14 */ 15 changeUI() { 16 this.message = "子组件UI更新了" 17 } 18 19 build() { 20 Text(this.message) 21 .width("100%") 22 .height(50) 23 .backgroundColor(Color.Pink) 24 .textAlign(TextAlign.Center) 25 } 26}
触发事件
1@Entry 2@Component 3struct DemoPage { 4 build() { 5 Column() { 6 Child() 7 Button("点击") 8 .onClick(() => { 9 getContext().eventHub.emit('changeUI') 10 }) 11 } 12 .height('100%') 13 .width('100%') 14 .justifyContent(FlexAlign.Center) 15 } 16}
相关总结
也许大家可能会有疑问,子组件更新UI,直接由装饰器触发不就行了,希望大家能够明白,以上呢只是简单的案例,在实际的开发中,子组件方法中可能很多的逻辑,比如网络请求,比如数据存储等等,并不是简单的UI更新。
当然了,所举的实现方式也不是全的,可能也有着其它的方式可以实现,大家在实际的开发中选择适合的一种即可。
