news 2026/6/22 12:14:12

@Prop单向数据流:HarmonyOS6 PC父子组件传参的最佳实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@Prop单向数据流:HarmonyOS6 PC父子组件传参的最佳实践

在 HarmonyOS6 PC 开发中,组件拆分是日常操作。一个复杂的设置页面,你不可能把所有代码堆在一个build()方法里——拆成父子组件才是正路。那问题来了:父组件的数据怎么传给子组件?

@Prop 就是干这个的。说白了,它就是一个"只读通道"——父组件把数据丢给子组件,子组件拿着用,但不能改回去。简单、安全、单向流动。

@Prop 的核心规则:只能读,不能写

先看最基本的用法。父组件有一个计数器,子组件负责展示这个计数值:

@Componentstruct ChildCounter{@Propcount:number=0@Proplabel:string=''build(){Column(){Text(this.label).fontSize(12).fontColor('#999999')Text(this.count.toString()).fontSize(24).fontWeight(FontWeight.Bold).fontColor('#007DFF')}.width(80).height(80).backgroundColor('#F8F9FA').borderRadius(12).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)}}

子组件通过@Prop count: number声明"我需要一个叫 count 的数字"。父组件创建子组件时传值:

ChildCounter({count:this.parentCount,label:'原始值'})

这里有个铁律:子组件里不能对 @Prop 变量赋值。如果你写了this.count = 100,编译器会直接报错。这就是单向数据流的好处——数据只能从上往下流,子组件不会意外修改父组件的数据,排查 bug 的时候思路也清晰得多。

传递表达式:不只是传值,还能传计算结果

@Prop 传的不一定是原始值,你可以传一个表达式。这意味着父组件可以在传递的同时做计算,子组件拿到的是计算后的结果:

@Entry@Componentstruct PropDemo{@StateparentCount:number=0build(){Column(){Text('@Prop 父子传参').fontSize(18).fontWeight(FontWeight.Bold)// 父组件控制区Column(){Text(this.parentCount.toString()).fontSize(40).fontWeight(FontWeight.Bold).fontColor('#007DFF')Row({space:10}){Button('-1').onClick(()=>{this.parentCount--})Button('+1').onClick(()=>{this.parentCount++})Button('+10').onClick(()=>{this.parentCount+=10})Button('归零').onClick(()=>{this.parentCount=0})}.width('100%').justifyContent(FlexAlign.SpaceEvenly)}.width('100%').backgroundColor('#FFFFFF').borderRadius(12).padding(16)// 子组件展示区 —— 传递不同的表达式Column(){Row({space:12}){ChildCounter({count:this.parentCount,label:'原始值'})ChildCounter({count:this.parentCount*2,label:'×2'})ChildCounter({count:this.parentCount*3,label:'×3'})}.width('100%').justifyContent(FlexAlign.Center)}.width('100%').backgroundColor('#FFFFFF').borderRadius(12).padding(16).margin({top:10})}.width('100%').height('100%').backgroundColor('#F5F6FA').padding(16)}}

三个子组件,同一个parentCount,但传的值分别是原始值、两倍、三倍。父组件的数字一变,三个子组件同步更新。这种模式在数据看板类的 PC 应用中特别常见。

@Prop 支持哪些类型?

和 @State 类似,@Prop 也支持基本类型、对象和数组。但有个重要区别——@Prop 在子组件里是值的深拷贝

这意味着什么?父组件传一个对象给子组件,子组件拿到的是一个全新的拷贝。你在子组件里修改这个拷贝(假设能改的话),也不会影响父组件的原始对象。

不过实际上你改不了,因为 @Prop 变量在子组件中是只读的。

支持的类型清单:

  • numberstringboolean
  • 枚举
  • 对象和数组(深拷贝传递)

不支持的:

  • undefinednull
  • Promise
  • 函数

在 PC 端开发中的典型场景

@Prop 在 PC 端的应用场景远比移动端丰富,因为 PC 端的界面更复杂,组件拆分更细。来看看几个实战案例。

场景一:数据面板卡片

PC 端的仪表盘页面通常有好几张统计卡片,每张卡片展示不同的指标。这种场景天然适合 @Prop——父组件持有所有数据,子卡片只负责展示:

@Componentstruct StatCard{@Proptitle:string=''@Propvalue:string=''@Propunit:string=''@Proptrend:string=''@Propcolor:string='#007DFF'build(){Column(){Text(this.title).fontSize(12).fontColor('#999999')Row(){Text(this.value).fontSize(28).fontWeight(FontWeight.Bold).fontColor(this.color)Text(this.unit).fontSize(12).fontColor('#999999').margin({left:4,bottom:4})}.margin({top:4})Text(this.trend).fontSize(11).fontColor(this.trend.startsWith('+')?'#6BCB77':'#FF6B6B').margin({top:2})}.width('23%').padding(16).backgroundColor('#FFFFFF').borderRadius(12).alignItems(HorizontalAlign.Start)}}@Entry@Componentstruct DashboardDemo{@StatetotalUsers:number=12580@StateactiveUsers:number=8932@Staterevenue:number=456000@StategrowthRate:number=12.5build(){Column(){Text('数据看板').fontSize(20).fontWeight(FontWeight.Bold).margin({bottom:16})Row({space:12}){StatCard({title:'总用户数',value:this.totalUsers.toString(),unit:'人',trend:'+5.2%',color:'#007DFF'})StatCard({title:'活跃用户',value:this.activeUsers.toString(),unit:'人',trend:'+8.1%',color:'#6BCB77'})StatCard({title:'营收',value:(this.revenue/10000).toFixed(1),unit:'万元',trend:'+12.5%',color:'#FFD93D'})StatCard({title:'增长率',value:this.growthRate.toFixed(1),unit:'%',trend:'-2.3%',color:'#FF6B6B'})}.width('100%').justifyContent(FlexAlign.SpaceBetween)// 模拟数据刷新Button('刷新数据').margin({top:16}).onClick(()=>{this.totalUsers+=Math.floor(Math.random()*100)this.activeUsers+=Math.floor(Math.random()*50)this.revenue+=Math.floor(Math.random()*10000)this.growthRate=parseFloat((Math.random()*20-5).toFixed(1))})}.width('100%').height('100%').backgroundColor('#F5F6FA').padding(20)}}

四张卡片各自独立,但数据来源全在父组件。点一下"刷新数据",所有卡片同步更新。代码结构清晰,每张卡片的 UI 逻辑都封装在StatCard里。

场景二:导航标签栏

PC 端应用的侧边导航或顶部标签栏也是 @Prop 的好舞台。当前选中的标签由父组件管理,子组件只负责展示和接收状态:

@Componentstruct NavTab{@Propicon:string=''@Proplabel:string=''@PropisActive:boolean=false@PropbadgeCount:number=0build(){Row(){Text(this.icon).fontSize(18)Text(this.label).fontSize(13).margin({left:8}).fontColor(this.isActive?'#007DFF':'#333333')if(this.badgeCount>0){Text(this.badgeCount.toString()).fontSize(10).fontColor('#FFFFFF').backgroundColor('#FF6B6B').borderRadius(8).padding({left:5,right:5,top:1,bottom:1}).margin({left:8})}Blank()if(this.isActive){Column().width(3).height(20).backgroundColor('#007DFF').borderRadius(2)}}.width('100%').padding({left:16,right:12,top:10,bottom:10}).backgroundColor(this.isActive?'#E8F0FE':'#FFFFFF').borderRadius(8)}}@Entry@Componentstruct NavigationDemo{@StateactiveTab:number=0build(){Row(){// 侧边导航Column({space:4}){NavTab({icon:'📊',label:'数据看板',isActive:this.activeTab===0})NavTab({icon:'👥',label:'用户管理',isActive:this.activeTab===1,badgeCount:3})NavTab({icon:'📦',label:'订单列表',isActive:this.activeTab===2,badgeCount:12})NavTab({icon:'⚙️',label:'系统设置',isActive:this.activeTab===3})}.width(200).padding(8).backgroundColor('#FFFFFF')// 内容区Column(){Text(`当前页面:${['数据看板','用户管理','订单列表','系统设置'][this.activeTab]}`).fontSize(18).fontWeight(FontWeight.Bold)Row({space:8}){Button('数据看板').onClick(()=>{this.activeTab=0})Button('用户管理').onClick(()=>{this.activeTab=1})Button('订单列表').onClick(()=>{this.activeTab=2})Button('系统设置').onClick(()=>{this.activeTab=3})}.margin({top:16})}.layoutWeight(1).padding(20).backgroundColor('#F5F6FA')}.width('100%').height('100%')}}

侧边导航的激活状态完全由父组件的activeTab控制,每个 NavTab 只是被动接收状态来渲染。这种"状态提升"的模式在 PC 端布局中很经典。

场景三:进度指示器

PC 端的任务管理或文件上传场景经常需要进度展示。用 @Prop 做一个通用的进度卡片组件:

@Componentstruct ProgressCard{@ProptaskName:string=''@Propprogress:number=0@ProptotalSize:string=''build(){Column(){Row(){Text(this.taskName).fontSize(14).layoutWeight(1)Text(`${this.progress}%`).fontSize(13).fontColor('#007DFF')}.width('100%')Stack({alignContent:Alignment.Start}){Column().width('100%').height(6).backgroundColor('#E0E0E0').borderRadius(3)Column().width(`${this.progress}%`).height(6).backgroundColor(this.progress>=100?'#6BCB77':'#007DFF').borderRadius(3)}.width('100%').margin({top:8})Text(`总大小:${this.totalSize}`).fontSize(11).fontColor('#999999').margin({top:4})}.width('100%').padding(14).backgroundColor('#FFFFFF').borderRadius(10)}}

父组件持有各个任务的进度值,传给子组件展示。进度条的颜色、宽度、百分比文字全部由 @Prop 驱动。

@Prop 和 @State 的关系

很多人会混淆 @Prop 和 @State,其实它们的关系很清晰:

  • @State:组件自己拥有这个状态,可以读写,变化时触发自身 UI 更新。
  • @Prop:组件从父组件接收这个值,只读不可写,父组件的值变了会自动同步过来。

一个变量要么用 @State 自己管理,要么用 @Prop 从父组件接收,不能同时是两个。

还有一个容易搞混的点:@Prop 接收的是值拷贝,不是引用。父组件传一个数字 10 给子组件,子组件的 @Prop 存的是 10 这个值的拷贝。父组件后来改成 20,子组件的 @Prop 也会变成 20(因为框架做了同步),但子组件拿到的始终是一份独立的拷贝。

什么时候用 @Prop,什么时候用别的?

@Prop 适合"纯展示"型子组件——你传什么它显示什么,它不产生新数据。但如果你需要子组件能修改数据并同步回父组件,那就该用 @Link 了(下一篇文章会详细讲)。

简单判断标准:

  • 子组件只读数据,不改数据 → @Prop
  • 子组件需要修改数据,且修改要同步回父组件 → @Link
  • 需要跨多层传递数据,不想逐层写 @Prop → @Provide / @Consume

PC 端组件设计的建议

在 PC 端做组件拆分时,我一般遵循这个原则:尽量把 @State 往上提,让大多数子组件用 @Prop

为什么?因为状态集中管理比分散管理好调试。一个页面的核心数据放在顶层组件用 @State 管理,下面的子组件全部通过 @Prop 接收。这样数据流向永远是自上而下的,出了问题从上往下排查就行。

如果把 @State 散落在各个子组件里,时间一长你自己都搞不清哪个组件持有哪份数据,多个组件之间的状态同步更是噩梦。

这个思路和 React 社区提倡的"状态提升"(Lifting State Up)是相通的,好思路不分框架。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/22 12:14:07

架构演进与性能突破:BilibiliDown如何重塑视频下载体验

架构演进与性能突破:BilibiliDown如何重塑视频下载体验 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/…

作者头像 李华
网站建设 2026/6/14 3:56:22

【Sora 2超低比特率生存指南】:从128kbps到4K@60fps的7步重构法,NVIDIA工程师紧急封存的3项未公开API调用链

更多请点击: https://kaifayun.com 第一章:Sora 2比特率优化的底层范式迁移 传统视频生成模型普遍依赖高码率连续帧重建,而 Sora 2 的比特率优化并非简单压缩,而是将时空表征从“像素流”重构为“语义-运动双通道稀疏编码”。这一…

作者头像 李华
网站建设 2026/6/14 3:56:34

【agent第3篇】agent上下文+面经

9.上下文工程在之前的章节中,我们为智能体引入了记忆与工具能力。然而,要让Agent在真实复杂场景中稳定地“思考”与“行动”,仅有记忆与检索还不够——我们还需要一套系统化的工程方法,持续为模型构造恰当的上下文。这就是本章的主…

作者头像 李华
网站建设 2026/6/14 3:56:34

计算机毕业设计之django基于Django黄河文化资源管理系统

本文首先实现了黄河文化资源管理系统的发展随后依照传统的软件开发流程,最先为系统挑选适用的言语和软件开发平台,依据需求分析开展控制模块制做和数据库查询构造设计,随后依据系统整体功能模块的设计,制作系统的功能模块图、E-R图…

作者头像 李华