news 2026/7/14 2:06:52

鸿蒙原生开发手记:徒步迹 - @State/@Prop/@Link 状态管理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸿蒙原生开发手记:徒步迹 - @State/@Prop/@Link 状态管理

掌握 ArkUI 装饰器体系,构建响应式 UI


一、前言

状态管理是声明式 UI 框架的核心。ArkUI 提供了一套装饰器体系,让开发者声明式地定义组件状态和依赖关系,框架自动追踪状态变化并更新 UI。

本文将详解 @State、@Prop、@Link 三个最基础也最重要的装饰器。


二、状态管理概览

ArkUI 装饰器按作用范围分为三层:

装饰器作用范围用途
@State组件内部组件私有状态
@Prop父→子父组件向子组件传数据
@Link父子双向父子组件双向同步
@Provide跨级传递祖先→后代(提供者)
@Consume跨级传递后代→祖先(消费者)
@Watch状态监听监听状态变化回调
@ObjectLink对象属性监听对象属性级变化

三、@State - 组件私有状态

3.1 基本用法

@Componentstruct StepCounter{@StatestepCount:number=0;// 状态变量@StateisRecording:boolean=false;@StaterouteName:string='';build(){Column(){Text(`步数:${this.stepCount}`)// 自动响应变化.fontSize(20);Button('加1').onClick(()=>{this.stepCount++;// 状态变化,UI 自动更新});Button(this.isRecording?'记录中':'开始记录').backgroundColor(this.isRecording?'#FF6F00':'#4CAF50').onClick(()=>{this.isRecording=!this.isRecording;});}}}

3.2 @State 的深层变化监听

@Componentstruct RouteDisplay{@Stateroute:HikingRoute={id:1,name:'香山徒步',distance:8.5,tags:['森林','山景'],};build(){Column(){Text(this.route.name).fontSize(18);// 修改对象属性 - @State 会自动监听深层变化Button('修改名称').onClick(()=>{this.route={...this.route,name:'新路线名',// 重新赋值触发更新};});}}}

注意:@State 监听的是赋值操作,修改对象属性时需要重新赋值才会触发更新。对于数组,需要使用新数组替换。


四、@Prop - 父传子

@Prop 用于父组件向子组件传递数据,是单向数据流:

// 子组件 - 接收父组件传入的数据@Componentstruct RouteCard{@ProprouteName:string='';// 从父组件接收@Propdistance:number=0;@Propdifficulty:string='简单';build(){Column(){Text(this.routeName).fontSize(16).fontWeight(FontWeight.Bold);Text(`距离:${this.distance}km`).fontSize(14).fontColor('#666');Text(`难度:${this.difficulty}`).fontSize(12).fontColor(this.getDifficultyColor());}.padding(12).backgroundColor('#FFF').borderRadius(8);}getDifficultyColor():ResourceColor{if(this.difficulty==='简单')return'#4CAF50';if(this.difficulty==='中等')return'#FF9800';return'#F44336';}}// 父组件 - 传入数据@Entry@Componentstruct RouteListPage{build(){Column(){RouteCard({routeName:'香山徒步',distance:8.5,difficulty:'中等',});}.padding(16);}}

@Prop 的限制

  • 子组件不能修改 @Prop 的值(只读)
  • 父组件数据变化时,@Prop 自动同步更新
  • @Prop 是深拷贝,不会影响父组件原始数据

五、@Link - 父子双向同步

@Link 实现父子组件间的数据双向同步:

// 子组件@Componentstruct RecordingControl{@Link@Watch('onStatusChanged')status:string;// 双向绑定@Linkduration:number;onStatusChanged():void{console.log(`状态变更为:${this.status}`);}build(){Column(){// 子组件修改 @Link 变量 → 父组件同步更新Button(this.status==='recording'?'暂停':'继续').onClick(()=>{this.status=this.status==='recording'?'paused':'recording';});Text(`时长:${this.duration}s`);}}}// 父组件@Entry@Componentstruct TrackingPage{@StaterecordingStatus:string='idle';@StaterecordingDuration:number=0;build(){Column(){Text(`状态:${this.recordingStatus}`).fontSize(16);// 使用 $ 前缀传递 @Link 引用RecordingControl({status:$recordingStatus,duration:$recordingDuration,});}}}

$ 语法

使用$变量名将 @State 变量的引用传递给 @Link:

// 父组件传递ChildComponent({propVar:this.stateVar,// @Prop: 传值linkVar:$stateVar,// @Link: 传引用})

六、实战:徒步迹状态管理

结合"徒步迹"的轨迹记录页面,实际演示状态管理的使用:

// TrackingPage.ets@Entry@Componentstruct TrackingPage{@StateisRecording:boolean=false;@StateisPaused:boolean=false;@Stateduration:number=0;@Statedistance:number=0;privatetimerId:number=-1;build(){Column(){// 统计数据区域Row(){StatItem({label:'时长',value:this.formatTime(this.duration)});StatItem({label:'距离',value:`${this.distance.toFixed(2)}`});StatItem({label:'配速',value:this.calcPace()});}.width('100%').padding(16);// 控制按钮区域Row(){if(!this.isRecording){Button('开始徒步').width(180).height(56).backgroundColor('#4CAF50').borderRadius(28).onClick(()=>this.startRecording());}else{Button(this.isPaused?'继续':'暂停').width(72).height(72).backgroundColor(this.isPaused?'#4CAF50':'#FF9800').borderRadius(36).onClick(()=>{if(this.isPaused)this.resumeRecording();elsethis.pauseRecording();});Button('停止').width(72).height(72).backgroundColor('#F44336').borderRadius(36).margin({left:40}).onClick(()=>this.stopRecording());}}.padding({bottom:40});}.width('100%').height('100%');}startRecording():void{this.isRecording=true;this.timerId=setInterval(()=>{this.duration++;this.distance+=0.005;},1000);}pauseRecording():void{this.isPaused=true;clearInterval(this.timerId);}resumeRecording():void{this.isPaused=false;this.startTimer();}stopRecording():void{this.isRecording=false;this.isPaused=false;clearInterval(this.timerId);// 重置数据this.duration=0;this.distance=0;}startTimer():void{this.timerId=setInterval(()=>{this.duration++;this.distance+=0.005;},1000);}formatTime(seconds:number):string{constm=Math.floor(seconds/60);consts=seconds%60;return`${m.toString().padStart(2,'0')}:${s.toString().padStart(2,'0')}`;}calcPace():string{if(this.distance<=0)return'0\'00"';constpace=this.duration/this.distance;return`${Math.floor(pace/60)}'${Math.floor(pace%60).toString().padStart(2,'0')}"`;}}@Componentstruct StatItem{@Proplabel:string='';@Propvalue:string='';build(){Column(){Text(this.value).fontSize(24).fontWeight(FontWeight.Bold);Text(this.label).fontSize(13).fontColor('#666');}.alignItems(HorizontalAlign.Center);}}

七、@State 最佳实践

  1. 最小化状态:只保留需要 UI 响应的变量
  2. 避免冗余:能从其他状态推导的值不要单独声明
  3. 类型明确:始终为 @State 变量提供初始值
  4. 不可变性:尽量使用只读接口
// 好 - 状态最小化@Statedistance:number=0;// 只需存储基础数据// 配速由 duration 和 distance 计算得出,不需要额外状态// 不好 - 状态冗余@Statedistance:number=0;@Statepace:string='0\'00"';// 可以从 distance/duration 推导

八、总结

本文详细介绍了 ArkUI 状态管理的三个核心装饰器:@State(组件私有)、@Prop(父传子)、@Link(双向同步)。理解它们的区别和适用场景,是构建正确响应式 UI 的关键。

下一篇文章将学习跨组件通信的 @Provide/@Consume 装饰器。


下一篇预告:鸿蒙原生开发手记:徒步迹 - @Provide/@Consume 跨组件通信

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

鸿蒙原生开发手记:徒步迹 - @Provide/@Consume 跨组件通信

掌握跨级组件通信&#xff0c;构建灵活可复用的组件体系一、前言 在复杂应用中&#xff0c;经常出现祖先组件需要向后代组件传递数据的场景。如果逐层通过 Prop 传递&#xff0c;会导致"属性逐层传递"的问题&#xff08;prop drilling&#xff09;&#xff0c;代码冗…

作者头像 李华
网站建设 2026/7/14 2:03:19

AI绘画实战:用Stable Diffusion将文字描述转化为魔法少女OC变身图

在数字艺术和角色设计领域&#xff0c;AI绘画工具的出现极大地降低了创作门槛&#xff0c;使得即使没有深厚美术功底的人也能将脑海中的想象转化为视觉形象。特别是对于“魔法少女”这类充满幻想元素的原创角色&#xff08;OC&#xff09;&#xff0c;其华丽的变身过程、独特的…

作者头像 李华
网站建设 2026/7/14 2:02:05

数据科学家不是安全威胁,而是未被防护的工作流节点

1. 项目概述&#xff1a;当数据科学家成为组织数据安全的“隐性单点故障”你有没有遇到过这样的场景&#xff1a;一个紧急的数据分析需求压下来&#xff0c;业务部门催着要结果&#xff0c;模型上线时间卡在下周三&#xff0c;而数据科学家小张正对着本地笔记本上跑着的Jupyter…

作者头像 李华
网站建设 2026/7/14 2:01:08

用Python构建可配置AI人格系统

1. 项目概述&#xff1a;这不是在写聊天机器人&#xff0c;而是在“养”一个有呼吸感的AI角色你有没有试过和某个AI对话时&#xff0c;突然被一句带点小调侃、略带犹豫、甚至故意卖个关子的回复击中&#xff1f;不是那种“您好&#xff0c;我是AI助手&#xff0c;很高兴为您服务…

作者头像 李华