HarmonyOS7带结果返回页面实战:返回上一页时携带结果数据
文章目录前言如果准备复刻先盯住这几块这部分最容易被低估状态关系这一页的控制权主要在这里第一段关键代码页面是怎么被带起来的第二段关键代码真正决定交互手感的地方第一次跑这个案例我会怎么试这一页真正落地时建议额外处理什么把它吃透之后后面会省很多时间完整代码收个尾前言跳到子页面选完东西再把结果带回上一页这是业务里最常见的交互之一。地址选择、标签选择、头像裁剪基本都属于这一类。这个案例很实用。 有些案例看完只会得到一个 demo 效果有些案例看完会顺手带走一套页面组织方法。我的目标是把它往后者那边讲。如果把这页当成练习材料我会优先看它怎样围绕 返回上一页时携带结果数据 组织页面。因为这一层想清楚了后面的代码基本就不会散。这类写法尤其适合落在 选择器、编辑确认、表单辅助页 这些场景里所以我下面不会只讲“组件怎么写”而是更关心“放进页面之后为什么这样组织”。如果准备复刻先盯住这几块很多人学示例会直接复制 UI 代码结果复刻出来是像的但后面一改就散。原因通常不是代码抄错了而是结构关系没先看懂。页面区域主要职责在代码里的典型表现头部说明区交代当前案例在演示什么Text标题、补充说明、标签文案核心展示区承载组件能力的主要效果Column、Row、业务组件本体辅助信息区补充状态、标签、分组或统计信息次级文本、角标、分组标题、描述块交互入口区负责切换、返回、定位、选择等动作点击事件、按钮、索引条、导航入口这一页没有额外拆出接口页面更多是直接围绕基础数据和组件参数展开。这类页面最容易被忽略的往往不是功能而是手感、反馈和节奏我会把这些细点单独挑出来说。这部分最容易被低估状态关系如果一个示例后续不好改十有八九不是布局有问题而是状态职责没分开。这个案例刚好适合拿来观察这件事。isShow建议优先确认它控制的是显示、选择、切换还是数据同步。showDetail建议优先确认它控制的是显示、选择、切换还是数据同步。selectedItem建议优先确认它控制的是显示、选择、切换还是数据同步。returnedResult建议优先确认它控制的是显示、选择、切换还是数据同步。selectedColor建议优先确认它控制的是显示、选择、切换还是数据同步。真要自己上手改我建议别一开始就扑到样式上先把状态分层这件事处理好长期数据列表内容、卡片信息、导航目标、角标基数这类不该跟着一次点击乱跳的内容。交互状态当前选中项、弹层开关、吸附开关、回显结果这类会频繁变化的值。计算结果过滤结果、统计文案、高亮判断这类更适合派生出来的内容。这一页的控制权主要在这里示例代码里最怕被忽略的就是那些看起来普通、实际上掌控页面节奏的方法。这里建议优先把它们摸清。这个案例没有太多额外方法核心价值主要集中在页面结构和组件组合方式。我自己读这类方法时通常只抓一条线谁触发、谁被改、页面哪里立刻有反馈。把这三件事连起来很多交互代码一下就顺了。第一段关键代码页面是怎么被带起来的这一段建议慢一点看。它通常决定了页面初始状态也决定了后续哪些区域会跟着刷新。StateisShow:booleantrueStateshowDetail:booleanfalseStateselectedItem:stringStatereturnedResult:stringStateselectedColor:stringprivateitems:string[][红色,蓝色,绿色,橙色]build(){Column(){if(this.isShow){Column({space:16}){Text(带参数返回).fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)Text(NavDestination 返回时携带结果数据到上一页).fontSize(13).fontColor(DEMO_SUBTEXT_COLOR).width(100%)// 主页面if(!this.showDetail){Column({space:12}){这一段我通常不会一下翻过去而是先确认下面这几个判断点State字段到底在控制显示、选择、跳转结果还是模式切换。默认值是不是合理页面一打开会不会就落在一个可理解的状态上。字段命名能不能让后来的人一眼看懂用途而不是还要翻半天 UI。第二段关键代码真正决定交互手感的地方这一段代码先在点击时写入selectedItem和selectedColor再切到确认页。等用户确认后结果才会写进returnedResult并回到主页面。这个流程把“选择中”和“已返回”分开了读起来比直接改主页面结果安全。.onClick((){this.selectedItemitemthis.selectedColor[DEMO_THEME_COLOR,PRESET_COLORS[0].value,PRESET_COLORS[1].value,PRESET_COLORS[2].value][index]this.showDetailtrue})})}.width(100%)}.width(100%)}else{// 确认页面Column({space:16}){Row(){Text(← 取消).fontSize(14).fontColor(DEMO_SUBTEXT_COLOR).onClick((){this.showDetailfalse})Blank()Text(选择确认).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#333333)}代码读到这里我通常会顺手补三件事不然后面很容易只看热闹这个交互入口接收的到底是什么输入。输入进来之后代码改了哪个状态或者触发了哪次导航。变化发生后用户最先感知到的反馈会落在哪个区域。这三个问题串起来之后这一页基本就不只是“看过”而是真的读懂了。第一次跑这个案例我会怎么试第一次接触这个案例时不要急着扩展功能。先把默认状态和一次完整交互跑顺后面加东西才不会歪。先进入页面确认首屏是不是把带结果返回页面的主题交代清楚。盯住核心展示区观察默认状态下最醒目的内容是什么。主动触发一次关键交互比如点击、滑动、跳转、返回、切换或者选择。回头检查状态区、提示区、标题区或者附属信息有没有跟着变化。最后再打开源码对照刚才那次交互把状态变化链路串起来。如果这五步你能边操作边说清楚页面发生了什么后面再换成自己的数据和交互心里会稳很多。这一页真正落地时建议额外处理什么我自己迁示例代码时最怕的是把展示逻辑和业务逻辑粘成一团。这个案例里有些地方可以提前规避。导航类页面迁到业务里时最先要补的是参数类型和返回结果约定而不是视觉样式。如果页面层级开始变多建议尽早把跳转入口、回退逻辑和标题栏动作拆成清晰边界。只要页面里有重复块就别硬撑着手写到底早点抽成小组件后面改样式和改交互都会轻松很多。示例数据最好和布局代码分开放不然后面一接接口页面文件很容易立刻变臃肿。把它吃透之后后面会省很多时间我会把这类案例当成“工程感比炫技感更强”的材料来留存。后面真的要做同类页面时能少走不少弯路。页面结构比较稳后续不管是换数据还是换皮肤成本都不会特别高。状态数量总体可控适合拿来练“一个页面里如何分配职责”这件事。组件参数和页面目标之间关系比较直观不太会出现“能跑但看不懂为什么这么配”的情况。完整代码下面保留整理过命名的完整 ArkTS 代码方便你直接对照学习。这里已经去掉原始的 Demo 命名改成了更贴近当前案例语义的名称。/** * 带结果返回页面 */import{PRESET_COLORS,generateListItems,DEMO_BG_COLOR,DEMO_CARD_COLOR,DEMO_THEME_COLOR,DEMO_SUBTEXT_COLOR}from./typesEntryComponentstruct RouteReturnWithResult{StateisShow:booleantrueStateshowDetail:booleanfalseStateselectedItem:stringStatereturnedResult:stringStateselectedColor:stringprivateitems:string[][红色,蓝色,绿色,橙色]build(){Column(){if(this.isShow){Column({space:16}){Text(带参数返回).fontSize(20).fontWeight(FontWeight.Bold).fontColor(DEMO_THEME_COLOR)Text(NavDestination 返回时携带结果数据到上一页).fontSize(13).fontColor(DEMO_SUBTEXT_COLOR).width(100%)// 主页面if(!this.showDetail){Column({space:12}){// 返回结果展示if(this.returnedResult){Column({space:8}){Text(返回的结果).fontSize(13).fontWeight(FontWeight.Medium).fontColor(#333333).width(100%)Row({space:10}){Circle({width:20,height:20}).fill(this.selectedColor)Text(this.returnedResult).fontSize(14).fontWeight(FontWeight.Bold).fontColor(this.selectedColor).layoutWeight(1)}}.width(100%).padding(12).backgroundColor(#F5F5F5).borderRadius(8)}Text(请选择一个选项).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#333333).width(100%)Row({space:10}){ForEach(this.items,(item:string,index:number){Column({space:6}){Circle({width:36,height:36}).fill([DEMO_THEME_COLOR,PRESET_COLORS[0].value,PRESET_COLORS[1].value,PRESET_COLORS[2].value][index])Text(item).fontSize(12).fontColor(#333333)}.layoutWeight(1).padding(12).backgroundColor(DEMO_CARD_COLOR).borderRadius(10).justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center).onClick((){this.selectedItemitemthis.selectedColor[DEMO_THEME_COLOR,PRESET_COLORS[0].value,PRESET_COLORS[1].value,PRESET_COLORS[2].value][index]this.showDetailtrue})})}.width(100%)}.width(100%)}else{// 确认页面Column({space:16}){Row(){Text(← 取消).fontSize(14).fontColor(DEMO_SUBTEXT_COLOR).onClick((){this.showDetailfalse})Blank()Text(选择确认).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#333333)}.width(100%)Column({space:12}){Circle({width:60,height:60}).fill(this.selectedColor)Text(this.selectedItem).fontSize(22).fontWeight(FontWeight.Bold).fontColor(this.selectedColor)Text(确认选择此选项并返回结果).fontSize(13).fontColor(DEMO_SUBTEXT_COLOR)}.width(100%).padding(24).backgroundColor(DEMO_CARD_COLOR).borderRadius(12)Row({space:10}){Button(取消).fontSize(14).height(40).layoutWeight(1).backgroundColor(#EEEEEE).fontColor(#666666).borderRadius(20).onClick((){this.showDetailfalse})Button(确认返回).fontSize(14).height(40).layoutWeight(1).backgroundColor(this.selectedColor).fontColor(#FFFFFF).borderRadius(20).onClick((){this.returnedResult您选择了: this.selectedItemthis.showDetailfalse})}.width(100%)}.width(100%).padding(16).backgroundColor(DEMO_CARD_COLOR).borderRadius(12)}// 流程说明Column({space:6}){Text(数据流程).fontSize(12).fontColor(DEMO_SUBTEXT_COLOR)Row({space:6}){Text(选择项).fontSize(11).fontColor(#FFFFFF).backgroundColor(DEMO_THEME_COLOR).padding({left:8,right:8,top:3,bottom:3}).borderRadius(6)Text(→).fontSize(11).fontColor(#999999)Text(NavDestination).fontSize(11).fontColor(#FFFFFF).backgroundColor(PRESET_COLORS[1].value).padding({left:8,right:8,top:3,bottom:3}).borderRadius(6)Text(→).fontSize(11).fontColor(#999999)Text(带参返回).fontSize(11).fontColor(#FFFFFF).backgroundColor(PRESET_COLORS[0].value).padding({left:8,right:8,top:3,bottom:3}).borderRadius(6)}}.width(100%).padding(10).backgroundColor(#FAFAFA).borderRadius(8)}.alignItems(HorizontalAlign.Start)}Text(带结果返回页面 - 带参数返回).fontSize(12).fontColor(#999999).margin({top:12})}.width(100%).height(100%).backgroundColor(DEMO_BG_COLOR).padding(16)}}收个尾真放到日常开发里最有参考价值的往往不是花样最多的页面而是这种把关键决定摆得很清楚的案例。带结果返回页面 就属于这一类。