文章目录先看两个被观察的对象addScore() 比构造函数更值得看ObjectLink 适合拆子组件页面结构怎么看完整代码写在最后Observed和ObjectLink很适合讲“对象级响应式”但只讲概念会有点飘。这个案例把它放到用户资料和每日任务里就好理解多了用户积分变了资料卡要刷新任务完成了任务行也要刷新。这类页面如果只靠普通对象很容易出现“数据确实改了但 UI 没动”的情况。HarmonyOS7 里做对象监听关键就是把对象本身纳入响应式体系。先看两个被观察的对象代码里有两个Observed类UserProfile和Task。前者保存用户名、年龄、等级、头像和积分后者保存任务 id、标题、完成状态和奖励积分。它们不是随便写的普通类。加上Observed后子组件可以通过ObjectLink观察对象属性变化。这样父组件传给子组件的不是一份死数据而是可以继续响应更新的对象。addScore()比构造函数更值得看用户完成任务后积分会增加积分达到等级阈值时还会升级。这个逻辑放在UserProfile.addScore()里比散落在按钮点击事件中清楚很多。addScore(pts:number){this.scoreptsif(this.scorethis.level*100){this.levelthis.scorethis.score-(this.level-1)*100}}这段代码说明了一个很实用的写法对象自己的业务规则尽量放回对象内部。页面只负责触发动作不要把升级规则、积分计算、UI 刷新混在一个点击事件里。ObjectLink适合拆子组件像用户卡片、任务行这种组件如果每个字段都用Prop传参数会越来越多而且子组件无法自然感知对象内部变化。ObjectLink更适合这种“整对象传入局部字段更新”的场景。不过它也不是万能的。只有对象被Observed标记ObjectLink才有意义如果对象结构经常临时加字段ArkTS 的静态类型也不会喜欢这种写法。页面结构怎么看ObservedProfilePage里维护了userProfile和taskList。用户资料卡关注积分和等级每日任务列表关注完成状态。读代码时可以先看两个类再看子组件如何接收对象最后看完成任务时怎么更新积分。如果你做的是用户中心、任务系统、订单卡片这类页面这种写法比一堆零散State更容易维护。完整代码下面是完整代码。入口组件名是ObservedProfilePage适合拿来练习 HarmonyOS7 中对象状态监听和子组件刷新。// Observed 与 ObjectLink 对象监听ObservedclassUserProfile{name:stringage:numberlevel:numberavatar:stringscore:numberconstructor(name:string,age:number,level:number,avatar:string,score:number){this.namenamethis.ageagethis.levellevelthis.avataravatarthis.scorescore}addScore(pts:number){this.scoreptsif(this.scorethis.level*100){this.levelthis.scorethis.score-(this.level-1)*100}}}ObservedclassTask{id:numbertitle:stringdone:booleanpoints:numberconstructor(id:number,title:string,done:boolean,points:number){this.ididthis.titletitlethis.donedonethis.pointspoints}}// 子组件用户卡片ObjectLink 监听 UserProfileComponentstruct UserCard{ObjectLinkuser:UserProfilebuild(){Column({space:10}){Row({space:12}){Text(this.user.avatar).fontSize(36).width(60).height(60).textAlign(TextAlign.Center).backgroundColor(#EFF6FF).borderRadius(30)Column({space:4}){Text(this.user.name).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#111827)Row({space:8}){Text(Lv.${this.user.level}).fontSize(12).fontColor(Color.White).backgroundColor(#2563EB).padding({left:8,right:8,top:2,bottom:2}).borderRadius(10)Text(年龄${this.user.age}).fontSize(12).fontColor(#6B7280)}}.alignItems(HorizontalAlign.Start).layoutWeight(1)Column({space:2}){Text(this.user.score.toString()).fontSize(20).fontWeight(FontWeight.Bold).fontColor(#D97706)Text(积分).fontSize(11).fontColor(#9CA3AF)}.alignItems(HorizontalAlign.Center)}.width(100%).alignItems(VerticalAlign.Center)// 经验进度条Column({space:4}){Row(){Text(经验值).fontSize(12).fontColor(#6B7280).layoutWeight(1)Text(${this.user.score}/${this.user.level*100}).fontSize(12).fontColor(#2563EB)}Progress({value:this.user.score,total:this.user.level*100,type:ProgressType.Linear}).color(#2563EB).backgroundColor(#E5E7EB).style({strokeWidth:8}).width(100%)}}.width(100%).padding(16).backgroundColor(Color.White).borderRadius(12).shadow({radius:8,color:rgba(0,0,0,0.06),offsetY:2})}}// 子组件任务行ObjectLink 监听 TaskComponentstruct TaskRow{ObjectLinktask:TaskonComplete:(pts:number)void(){}build(){Row({space:12}){Text(this.task.done?✅:⬜).fontSize(22).onClick((){if(!this.task.done){this.task.donetruethis.onComplete(this.task.points)}})Column({space:3}){Text(this.task.title).fontSize(14).fontColor(this.task.done?#9CA3AF:#111827).decoration({type:this.task.done?TextDecorationType.LineThrough:TextDecorationType.None})Text(${this.task.points}积分).fontSize(12).fontColor(this.task.done?#9CA3AF:#D97706)}.alignItems(HorizontalAlign.Start).layoutWeight(1)if(!this.task.done){Text(去完成).fontSize(12).fontColor(#2563EB).backgroundColor(#EFF6FF).padding({left:10,right:10,top:4,bottom:4}).borderRadius(12).onClick((){this.task.donetruethis.onComplete(this.task.points)})}else{Text(已完成).fontSize(12).fontColor(#059669).backgroundColor(#D1FAE5).padding({left:10,right:10,top:4,bottom:4}).borderRadius(12)}}.width(100%).padding({left:16,right:16,top:12,bottom:12}).backgroundColor(this.task.done?#FAFAFA:Color.White).borderRadius(10).alignItems(VerticalAlign.Center)}}EntryComponentstruct ObservedProfilePage{StateuserProfile:UserProfilenewUserProfile(张三,25,3,‍,65)StatetaskList:Task[][newTask(1,完成每日签到,false,10),newTask(2,阅读一篇技术文章,false,20),newTask(3,完成一个练习项目,false,50),newTask(4,参与社区问答,false,30),newTask(5,分享学习心得,false,40),]build(){Column({space:0}){// 标题Text(Observed ObjectLink).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#111827).width(100%).padding({left:20,right:20,top:20,bottom:4})Text(监听对象内部属性变化实现嵌套数据驱动视图).fontSize(13).fontColor(#6B7280).width(100%).padding({left:20,right:20,bottom:12})// 说明Row(){Text().fontSize(14).margin({right:6})Text(Observed 类 ObjectLink 子组件对象属性变化时触发子组件重渲染).fontSize(12).fontColor(#1E40AF).layoutWeight(1)}.width(100%).padding({left:16,right:16,top:8,bottom:8}).backgroundColor(#DBEAFE).margin({bottom:12}).alignItems(VerticalAlign.Top)Scroll(){Column({space:12}){// 用户卡片UserCard({user:this.userProfile}).margin({left:20,right:20})// 操作按钮Row({space:10}){Button(10 积分).fontSize(12).fontColor(#D97706).backgroundColor(#FEF3C7).borderRadius(16).padding({left:14,right:14,top:8,bottom:8}).onClick((){this.userProfile.addScore(10)})Button(50 积分).fontSize(12).fontColor(#059669).backgroundColor(#D1FAE5).borderRadius(16).padding({left:14,right:14,top:8,bottom:8}).onClick((){this.userProfile.addScore(50)})Button(年龄1).fontSize(12).fontColor(#7C3AED).backgroundColor(#F5F3FF).borderRadius(16).padding({left:14,right:14,top:8,bottom:8}).onClick((){this.userProfile.age})}.padding({left:20,right:20})// 任务列表标题Text(每日任务完成任务获得积分).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#374151).padding({left:20})Column({space:8}){ForEach(this.taskList,(task:Task){TaskRow({task:task,onComplete:(pts:number){this.userProfile.addScore(pts)}}).margin({left:20,right:20})},(task:Task)task.id.toString())}// 已完成统计Row({space:12}){Text(✅).fontSize(20)Text(已完成${this.taskList.filter((t:Task)t.done).length}/${this.taskList.length}任务).fontSize(14).fontColor(#374151).layoutWeight(1)Text(${this.taskList.filter((t:Task)t.done).reduce((s:number,t:Task)st.points,0)}积分).fontSize(14).fontWeight(FontWeight.Bold).fontColor(#D97706)}.width(100%).padding({left:20,right:20,top:12,bottom:12}).backgroundColor(#FFFBEB).margin({bottom:24}).alignItems(VerticalAlign.Center)}}.layoutWeight(1)}.width(100%).height(100%).backgroundColor(#F9FAFB)}}写在最后这个例子不复杂但很适合反复看。很多 ArkUI 页面写不顺其实不是组件不会用而是状态、结构和反馈没有放在一起设计。