【鸿蒙南向开发】OpenHarmony应用组件间通信

51 篇文章 0 订阅
51 篇文章 0 订阅

前言

ETS(基于 TS 扩展的声明式开发范式)提供了强大的组件化能力,支持开发者高效的构建应用的 UI 界面,然而每一个组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互进行直接的引用,因此组件间的相互通信是非常重要的。

组件间通信原理

ETS 组件间通信是通过组合不同的装饰器来实现数据在各个组件之间的单向/双向传递。

相关装饰器介绍

在这里插入图片描述

组件间通信实现

父子组件通信

数据单向传递

使用 @State 和 @Prop 装饰器可以实现父组件向子组件单向传递数据。

●定义子组件 Child

@Component
struct Child {
    @Watch("listenChildCount") //当count变量值发生变化,会调用listenChildCount()
    @Prop
    count: number;
    build() {
        Column() {
                Text("子组件:" + this.count).fontSize(30)
                Button("reduce")
                    .fontSize(25)
                    .onClick(() => {
                        this.count--;
                    })
            }
            .border({ width: 2, color: Color.Blue })
            .backgroundColor(Color.Green)
            .width("50%")
            .height("50%")
    }

    /**
     * 用于监听count变量的变化
     */
    listenChildCount() {
        console.info("ChildComponent count changed:" + this.count)
    }
}

●定义父组件,在父组件中嵌套子组件 Child,并将父组件中的 count 变量传递给子组件

@Entry
@Component
struct Parent {
    @State
    @Watch("listenCount") //当count变量值发生变化,会调用listenCount()
    count: number = 0;
    build() {
        Column() {
            Column() {
                    Text("父组件:" + this.count)
                        .fontSize(30)
                        .fontColor(Color.Red)
                    Button("add")
                        .fontColor(Color.White)
                        .fontSize(30)
                        .backgroundColor(Color.Orange)
                        .onClick(() => {
                            this.count++;
                        })
                    Child({ count: this.count })
                }.border({ width: 2, color: Color.Black })
                .width("100%")
                .height(400)
                .backgroundColor(Color.Gray)
        }
    }
    listenCount() {
        console.info("ParentComponent count changed:" + this.count)
    }
}

效果如下:
在这里插入图片描述

数据双向传递

@State/@Link 实现父子组件数据双向传递

●将上文的子组件中 count 变量上的装饰器改为 @Link

@Component
struct Child {
    @Link
    @Watch("listenCount")
    count: number;
    build() {
            ...
            ...
        }
        ...
}
​

●改变上文中父组件传递数据到子组件的方式

@Entry
@Component
struct Parent {
    ...
    build() {
        Column() {
            ...
            ...
            Child({ count: $count }) //@Link需要用'$'符号传递变量
        }.border({ width: 2, color: Color.Black })
        .width("100%")
        .height(400)
        .backgroundColor(Color.Gray)

    }
    ...
}
​

效果如下:

在这里插入图片描述

@Provide/@Consume 实现父子组件数据双向传递

将上文父组件中 count 变量上的装饰器替换为 @Provide,子组件中 count 变量上的装饰器替换成 @Consume:

@Entry
@Component
struct Parent {
    //这里@Provide必须放在@Watch的上面,否则会报错
    @Provide("Count")
    @Watch("listenCount") //当count变量值发生变化,会调用listenCount()
    count: number = 0;
    build() {
        Column() {
            Column() {
                    Text("父组件:" + this.count)
                        .fontSize(30)
                        .fontColor(Color.Red)

                    Button("add")
                        .fontColor(Color.White)
                        .fontSize(30)
                        .backgroundColor(Color.Orange)
                        .onClick(() => {
                            this.count++;
                        })
                    Child() //使用@Provide 、@Consume不需要像@Link、@Prop那样传数据
                }.border({ width: 2, color: Color.Black })
                .width("100%")
                .height(400)
                .backgroundColor(Color.Gray)
        }
    }
    listenCount() {
        console.info("ParentComponent count changed:" + this.count)
    }
}

@Component
struct Child {
    //这里@Consume必须放在@Watch的上面,否则会报错
    @Consume("Count") //@Consume的参数值必须和对应的@Provide的参数值一致
    @Watch("listenChildCount") //当count变量值发生变化,会调用listenChildCount()
    count: number;
    build() {
        Column() {
            Text("子组件:" + this.count)
                .fontSize(30)
            Button("reduce")
                .fontSize(25)
                .onClick(() => {
                    this.count--;
                })
        }
        .border({ width: 2, color: Color.Blue })
        .backgroundColor(Color.Green)
        .width("50%")
        .height("50%")
    }
    listenChildCount() {
        console.info("ChildComponent count changed:" + this.count)
    }
}
​

效果:效果与上一步相同

@Provide/@Consume 实现组件跨层级双向传递数据

●定义子组件 GrandChild

@Component
struct GrandChild {
    @Consume
    count: number;
    build() {
        Column() {
            Text("GrandChild:" + this.count)
                .fontSize(30)
            Button("reduce")
                .fontSize(25)
                .onClick(() => {
                    this.count--;
                })
        }
        .border({ width: 2, color: Color.Blue })
        .backgroundColor(Color.Gray)
        .width(200)
        .height(180)
    }
}

●定义子组件 Child,在 Child 组件中嵌套 GrandChild 组件

@Component
struct Child {
    build() {
        Column() {
            Text("Child")
                .fontSize(40)
                .margin({ top: 25 })
            GrandChild()
        }
        .border({ width: 2, color: Color.Blue })
        .backgroundColor(Color.Green)
        .width(300)
        .height(300)
    }
}

●定义父组件 Parent,在 Parent 组件中嵌套 Child 组件

@Entry
@Component
struct Parent {
    @Provide("Count")
    count: number = 0;
    build() {
        Column() {
            Column() {
                Text("Parent:" + this.count)
                    .fontSize(30)
                    .fontColor(Color.Red)

                Button("add")
                    .fontColor(Color.White)
                    .fontSize(30)
                    .backgroundColor(Color.Orange)
                    .onClick(() => {
                        this.count++;
                    })
                Child()
            }.border({ width: 2, color: Color.Black })
            .width("100%")
            .height(400)
            .backgroundColor(Color.Gray)
        }
    }
}
​

效果如下:
在这里插入图片描述

兄弟组件通信

ETS 中要实现兄弟组件间传递数据需要借助第三个组件,即两个需要传递数据的组件需要有共同的父组件

@Provide/@Consume 实现兄弟组件双向传递数据

●定义子组件 Child1、Child2,并用 @Consume 装饰对应变量

@Component
struct Child1 {
    @Consume("Count")
    count1: number
    build() {
        Column() {
            Text("Child1:" + this.count1)
                .fontSize(40)
            Button("add")
                .fontColor(Color.White)
                .fontSize(30)
                .backgroundColor(Color.Orange)
                .onClick(() => {
                    this.count1++;
                })
        }
        .border({ width: 2, color: Color.Blue })
        .backgroundColor(Color.Green)
        .width("100%")
        .height(180)
    }
}

@Component
struct Child2 {
    @Consume("Count")
    count2: number;
    build() {
        Column() {
            Text("Child2:" + this.count2)
                .fontSize(30)
            Button("reduce")
                .fontSize(25)
                .onClick(() => {
                    this.count2--;
                })
        }
        .border({ width: 2, color: Color.Blue })
        .backgroundColor(Color.Yellow)
        .width("100%")
        .height(180)
    }
}
​

●定义父组件 Parent,嵌套组件 Child1、Child2

@Entry
@Component
struct Parent {
    @Provide("Count")
    count: number = 0;
    build() {
        Column() {
            Child1()
            Child2()
        }
        .width("100%")
        .height("100%")
    }
}
​

效果如下:

在这里插入图片描述

@State 和 @Link 实现兄弟组件双向传递数据

●将子组件 Child1 和 Child2 中 count 变量上的装饰器改为 @Link

@Component
struct Child1 {
    @Link
    count1: number
    build() {
        ...
        ..
    }

}
@Component
struct Child2 {
    @Link
    count2: number;
    build() {
        ...
        ...
    }
}
​

●将上一步父组件 Parent 中 count 变量上的装饰器改为 @State

@Entry
@Component
struct Parent {
    @State
    count: number = 0;
    build() {
        ...
        Child1({ count1: $count })
        Child2({ count2: $count })
            ...
    }
}
​

效果:与上一步的效果相同

任意组件通信

借助 AppStorage 和 @StorageLink 可以实现任意两个组件(包括同一个页面里的两个组件、不同页面里的组件、不同 Ability 里的两个组件)

AppStorage/@StorageLink 实现不同页面组件间传递数据

●定义页面 Page1

import router from '@ohos.router'; //router用于进行页面跳转
AppStorage.SetOrCreate("Count", 0); //先向AppStorage中存一个key:value
@Entry
@Component
struct Component1 {
    @StorageLink("Count")
    count: number = AppStorage.Link("Count") //与AppStorage进行双向绑定,用AppStorage里的值初始化count
    build() {
        Column() {
            Text("页面1:" + this.count)
                .fontSize(50)

            Button("add")
                .margin({ bottom: 25 })
                .onClick(() => {
                    this.count++;
                })
            Button("跳转")
                .fontSize(25)
                .onClick(() => {
                    router.push({ url: "pages/page2" })
                })
        }.border({ width: 2, color: Color.Blue })
        .width("100%")
        .height(400)
        .backgroundColor(Color.Gray)
    }
}
​

●定义页面 Page2

import router from '@ohos.router';
@Entry
@Component
struct Component2 {
    @StorageLink("Count")
    count: number = AppStorage.Link("Count") //与AppStorage进行双向绑定,用AppStorage里的值初始化count
    build() {
        Column() {
            Text("页面2:" + this.count)
                .fontSize(50)
                .fontColor(Color.Green)

            Button("reduce")
                .margin({ bottom: 25 })
                .onClick(() => {
                    this.count--;
                })
            Button("跳转")
                .fontSize(25)
                .onClick(() => {
                    router.back({ url: "pages/page1" })
                })
        }.border({ width: 2, color: Color.Blue })
        .width("100%")
        .height(400)
        .backgroundColor(Color.Orange)
    }
}
​

效果如下:
在这里插入图片描述

写在最后

●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing ,不定期分享原创知识。

在这里插入图片描述

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值