
文章目录前言一、什么是父子组件1.1 组件树的概念1.2 基本的组件拆分示例二、Prop父到子的单向传递2.1 Prop 的基本规则2.2 Prop 传递复杂对象三、Link父子双向绑定3.1 Link 的使用场景3.2 Link 的关键语法$$ 运算符四、回调函数通信子组件通知父组件4.1 使用函数参数传递回调五、三种通信方式总结对比总结前言随着项目越来越复杂UI 代码不可能全写在一个组件里。我们需要把界面拆分成多个子组件然后通过参数传递让父子组件协同工作。HarmonyOS ArkUI 提供了Prop单向传递和Link双向绑定两种机制满足不同场景的通信需求。本篇通过真实可运行代码带你掌握父子组件通信的所有核心技巧。一、什么是父子组件1.1 组件树的概念在 ArkUI 中每个Component就是一个组件。组件可以嵌套形成组件树MainPage父 └── Navigation └── GasStationPage子 ├── MapComponent子 ├── titleBuilder内联 Builder └── bindBuilder内联 Builder └── stationInfoCard内联 Builder相当于子组件父组件通过属性自定义参数向子组件传递数据子组件通过回调函数或Link向父组件反馈状态变化。1.2 基本的组件拆分示例把一个复杂卡片拆分为独立组件// 子组件加油站卡片Componentstruct StationCard{// 用 Prop 接收父组件传来的数据单向父→子PropstationName:string;PropstationAddr:string;Propdistance:string;build(){Row({space:12}){// 左侧图标Image($r(app.media.startIcon)).width(48).height(48).borderRadius(8)// 右侧信息Column({space:4}){Text(this.stationName).fontSize(16).fontWeight(FontWeight.Medium).fontColor(#333333)Text(this.stationAddr).fontSize(13).fontColor(#999999)}.alignItems(HorizontalAlign.Start).layoutWeight(1)// 距离显示Text(${this.distance}km).fontSize(14).fontColor(#1A6FF5)}.width(100%).padding(16).backgroundColor(#FFFFFF).borderRadius(12)}}// 父组件使用子组件EntryComponentstruct ParentPage{build(){Column({space:12}){// 像 HTML 属性一样传值StationCard({stationName:中国石化加油站,stationAddr:北京市海淀区中关村大街1号,distance:1.2})StationCard({stationName:中国石油加油站,stationAddr:北京市朝阳区建国路88号,distance:2.5})}.padding(16).width(100%)}}二、Prop父到子的单向传递2.1 Prop 的基本规则特性说明数据流向父组件 → 子组件单向子组件能否修改能但不影响父组件父组件更新时子组件的 Prop 值同步更新初始值必须提供默认值Componentstruct ChildWithProp{Proptitle:string默认标题;// 父组件传来子组件可读PropisActive:booleanfalse;build(){Text(this.title).fontColor(this.isActive?#1A6FF5:#999999).fontSize(16)}}2.2 Prop 传递复杂对象// 定义数据类型classCardInfo{title:string;subtitle:string;iconColor:string#1A6FF5;constructor(title:string,subtitle:string,iconColor?:string){this.titletitle;this.subtitlesubtitle;if(iconColor){this.iconColoriconColor;}}}Componentstruct InfoCard{PropcardInfo:CardInfonewCardInfo(,);build(){Column({space:8}){Row(){Circle().width(12).height(12).fill(this.cardInfo.iconColor)Text(this.cardInfo.title).fontSize(16).fontWeight(FontWeight.Bold).margin({left:8})}Text(this.cardInfo.subtitle).fontSize(13).fontColor(#666666)}.padding(16).width(100%).backgroundColor(#F8F9FA).borderRadius(12).alignItems(HorizontalAlign.Start)}}EntryComponentstruct PropObjectDemo{Statecards:CardInfo[][newCardInfo(附近加油站,为您找到 5 个加油站,#1A6FF5),newCardInfo(最近加油站,距您 1.2km,#52C41A),newCardInfo(优惠信息,今日 92# 汽油立减 0.1元/升,#FA8C16),];build(){Column({space:12}){ForEach(this.cards,(card:CardInfo){InfoCard({cardInfo:card})})}.padding(16).width(100%)}}提示传递对象时Prop 接收的是父组件对象的深拷贝子组件修改不影响父组件。三、Link父子双向绑定3.1 Link 的使用场景当子组件的操作需要改变父组件的状态时使用Link。比如子组件中有一个开关切换后要同步到父组件的状态变量。// 子组件带 Link 的开关Componentstruct ToggleSwitch{LinkisEnabled:boolean;// 双向绑定父组件的变量build(){Row({space:12}){Text(this.isEnabled?已开启:已关闭).fontSize(14).fontColor(this.isEnabled?#52C41A:#999999)Toggle({type:ToggleType.Switch,isOn:this.isEnabled}).onChange((isOn:boolean){this.isEnabledisOn;// 修改 Link 变量父组件同步更新}).selectedColor(#1A6FF5)}.width(100%).justifyContent(FlexAlign.SpaceBetween).padding({left:16,right:16,top:12,bottom:12}).backgroundColor(#FFFFFF).borderRadius(12)}}// 父组件EntryComponentstruct LinkDemo{StatelocationEnabled:booleanfalse;StatenotifyEnabled:booleantrue;build(){Column({space:12}){// 状态展示Column({space:4}){Text(当前设置状态).fontSize(14).fontColor(#999999)Text(定位${this.locationEnabled?开:关}| 通知${this.notifyEnabled?开:关}).fontSize(16).fontWeight(FontWeight.Bold).fontColor(#333333)}.width(100%).padding(16).backgroundColor(#F5F7FA).borderRadius(12)Text(应用设置).fontSize(18).fontWeight(FontWeight.Bold).alignSelf(ItemAlign.Start)// 传入 $变量名$$运算符表示 Link 绑定ToggleSwitch({isEnabled:$locationEnabled})ToggleSwitch({isEnabled:$notifyEnabled})}.padding(16).width(100%)}}3.2 Link 的关键语法$$运算符使用Link时父组件传参时要在变量名前加$// 父组件传递 Link 参数ChildComponent({myLinkVar:$parentStateVar})// ↑ 注意这个 $ 符号// 对比 Prop 传递不加 $ChildComponent({myPropVar:this.parentStateVar})在本项目中bindSheet也用了类似语法.bindSheet($$this.isShow,this.bindBuilder(),{// ...})$$this.isShow表示将isShow以双向绑定的方式传给bindSheet弹窗内部关闭时会自动修改isShow为false。四、回调函数通信子组件通知父组件4.1 使用函数参数传递回调除了 Link还可以通过函数回调实现子→父通信Componentstruct CounterButton{Proplabel:string按钮;// 回调函数父组件传入子组件调用onCountChange:(count:number)void(){};Stateprivatecount:number0;build(){Button(${this.label}:${this.count}).onClick((){this.count;this.onCountChange(this.count);// 通知父组件}).backgroundColor(#1A6FF5).fontColor(#FFFFFF).borderRadius(20).padding({left:20,right:20,top:10,bottom:10})}}EntryComponentstruct CallbackDemo{StatetotalCount:number0;Statelog:string[][];build(){Column({space:16}){Text(总计${this.totalCount}).fontSize(24).fontWeight(FontWeight.Bold)Row({space:12}){CounterButton({label:加油站A,onCountChange:(count:number){this.totalCount1;this.log[...this.log,A 被点击了${count}次];}})CounterButton({label:加油站B,onCountChange:(count:number){this.totalCount1;this.log[...this.log,B 被点击了${count}次];}})}// 显示最近3条日志Column({space:4}){ForEach(this.log.slice(-3),(item:string){Text(item).fontSize(13).fontColor(#666666)})}}.padding(24).width(100%).height(100%).justifyContent(FlexAlign.Center)}}五、三种通信方式总结对比父 ──── Prop ────→ 子 单向子修改不影响父 父 ←─── Link ────→ 子 双向子修改同步到父 父 ←─── callback ── 子 子主动调用父提供的函数通信方式适用场景语法特点Prop展示数据子组件不需要反馈父comp({ x: this.val })Link子组件需要修改父组件状态父comp({ x: $val })回调函数子组件事件通知父组件父comp({ onEvent: () {} })提示选择通信方式的原则——数据从哪来就从哪管。父组件拥有的数据用 Prop 传下去需要双向同步用 Link子组件触发事件用回调函数。总结父子组件通信是构建可复用、可维护 UI 组件的核心技能。Prop用于数据向下流Link用于状态双向绑定回调函数用于事件向上冒泡。三种方式各有适用场景灵活组合才能写出清晰解耦的组件树。下一篇我们来深入研究条件渲染和组件可见性控制。