当前位置: 首页 > news >正文

HarmonyOS 卡片详情到编辑闭环:router 参数、模板转实例与空白 fallback

HarmonyOS 卡片详情到编辑闭环:router 参数、模板转实例与空白 fallback

卡片工具最核心的链路是:从模板进入详情,添加到我的卡片,再进入编辑页保存,最后回到详情或管理页。如果这个链路里的 router 参数处理不清楚,就会出现详情页空白、模板误当用户卡片、编辑页字段回填错误等问题。

本章拆解CardDetailPage.etsCardEditPage.ets的实现。

详情页参数只接收 cardId 和 templateId

详情页的路由参数很克制:

interfaceRouteParams{cardId?:string;templateId?:string;}

页面不直接根据参数拼数据,而是交给服务层:

privaterefreshData():void{constparams:RouteParams=(router.getParams()??{})asRouteParams;constdetailView=appDataService.getCardDetailView(params.cardId,params.templateId);this.card=detailView.card;this.isTemplate=detailView.isTemplate;this.sceneTags=detailView.card.sceneTags.slice();this.desktopCardId=appDataService.getDesktopCardId();}

这样详情页只关心cardisTemplate。至于数据来自用户卡片、模板目录还是空白 fallback,由服务层处理。

模板和用户卡片共用一个详情页

详情页通过isTemplate控制主按钮文案:

privateprimaryActionText():string{if(this.isBlankTemplate()){return'新建卡片';}returnthis.isTemplate?'添加到我的卡片':'编辑当前卡片';}

这比拆两个详情页更省维护成本。模板详情和用户卡片详情的布局一样,只是动作不同。

模板转实例:先创建,再跳编辑

用户在模板详情里点击“添加到我的卡片”时,项目不会直接编辑模板,而是先创建一张用户卡片:

privatehandlePrimaryAction():void{if(this.isTemplate){if(this.card.templateId.length===0){router.pushUrl({url:RoutePaths.cardEdit});return;}constcreated=appDataService.createCardFromTemplate(this.card.templateId);router.pushUrl({url:RoutePaths.cardEdit,params:{cardId:created.id}});return;}router.pushUrl({url:RoutePaths.cardEdit,params:{cardId:this.card.id}});}

这里的关键是:编辑页收到的是cardId,不是templateId。模板已经被复制成用户卡片,后续编辑就应该保存到用户数据。

空白 fallback 避免参数缺失崩溃

如果详情页没有收到cardIdtemplateId,服务层会给出空白卡片。页面用isBlankTemplate()判断:

privateisBlankTemplate():boolean{returnthis.isTemplate&&this.card.templateId.length===0;}

这个 fallback 很重要。因为编辑页、新建入口、异常路由都可能出现空参数。如果页面假设router.getParams()一定有值,真机上很容易崩溃。

编辑页也只接收 cardId 和 templateId

编辑页参数同样简单:

interfaceRouteParams{cardId?:string;templateId?:string;}

然后通过服务层拿草稿:

privaterefreshData():void{constparams:RouteParams=(router.getParams()??{})asRouteParams;constdraft:CardDraftModel=appDataService.getCardDraft(params.cardId,params.templateId);this.draftId=draft.id;this.templateId=draft.templateId;this.title=draft.title;this.subtitle=draft.subtitle;this.detail=draft.detail;this.value=draft.value;this.footer=draft.footer;this.badge=draft.badge;this.categoryId=draft.categoryId;this.tone=draft.tone;this.favorite=draft.favorite;}

编辑页没有直接读持久化数组,也没有自己判断模板目录。

保存时用 replaceUrl 回详情页

保存卡片后,编辑页调用服务层保存,再替换当前路由为详情页:

privatesaveCard():void{constsaved=appDataService.saveCardDraft(this.currentDraft());router.replaceUrl({url:RoutePaths.cardDetail,params:{cardId:saved.id}});}

这里用replaceUrl的体验更好。保存后返回详情页,用户点返回不会回到已经保存过的编辑页。

详情页还承担桌面卡片设置

用户卡片详情页可以设置为桌面卡片:

privatehandleDesktopAction():void{if(this.isTemplate||this.card.id.length===0){return;}constupdated:boolean=appDataService.setDesktopCard(this.card.id);if(!updated){return;}this.desktopCardId=this.card.id;refreshDesktopForms();}

这里明确禁止模板直接设置为桌面卡片。只有保存成用户卡片后,才有稳定cardId可以同步给 Form。

页面文案跟状态走

详情页的摘要卡也根据状态生成:

privatesummaryCard():ShowcaseCardModel{return{id:this.card.id.length>0?this.card.id:'card-detail',title:this.card.title.length>0?this.card.title:'未命名卡片',subtitle:this.card.subtitle.length>0?this.card.subtitle:'查看说明、场景和使用状态',value:`${this.card.usageCount}次使用`,badge:this.isBlankTemplate()?'草稿':(this.isTemplate?'模板':(this.card.favorite?'收藏':'我的')),tone:this.card.tone,imageKey:imageKeyForTemplate(this.card.templateId,this.card.categoryId)};}

这种写法能让模板、草稿、我的卡片都复用同一套 UI。

验证清单

这条链路按下面场景测:

  1. 从分类模板列表进入详情,按钮显示“添加到我的卡片”。
  2. 点击添加后进入编辑页,URL 参数里应该是cardId
  3. 保存后进入详情页,详情页显示“我的卡片”状态。
  4. 用户卡片详情页点击收藏,状态立即刷新。
  5. 用户卡片详情页点击“设为桌面卡片”,桌面 Form 可刷新。
  6. 直接进入无参数详情页,不崩溃,显示空白新建状态。

小结

详情到编辑闭环的核心是参数语义清楚:templateId表示模板,cardId表示用户卡片,空参数进入 blank fallback。页面不要自己猜数据来源,统一让服务层输出视图模型。

这样模板市场、分类列表、首页预览、管理页编辑和桌面卡片设置都能走同一套详情编辑链路。

详情页的关键不是展示,而是“选中、刷新、跳转、回流”

卡片详情页容易写成展示页教程,但 Project028 的详情页真正承担的是卡片生命周期入口。用户从市场或分类进入详情,看到模板信息后,可以进入编辑页、设置为桌面卡片、打开系统桌面卡片管理器。这条链路必须把“状态写入”和“平台跳转”讲清楚。

CardDetailPage.ets中的桌面卡片入口先把当前卡片写入本地状态,再刷新已有桌面 Form,最后打开系统 Form 管理器。顺序不能随意调换:如果先打开系统管理器,用户添加的可能还是旧数据;如果只写本地状态不刷新已有 Form,已经添加到桌面的卡片不会跟随变化。

privateaddDesktopCard():void{if(!this.card){return;}appDataService.setDesktopFormCard(this.card.id);this.desktopCardId=this.card.id;refreshDesktopForms();this.openDesktopFormManager();}

打开系统管理器时还要传入 Form 维度、Form 名称和模块名。这里不是普通页面跳转,而是 HarmonyOS Form Kit 的系统入口。DESKTOP_FORM_DIMENSION_2_4表示当前工程选择 2x4 样式作为主规格;如果后续增加 2x2 或 4x4,不应该直接改掉这个常量,而是扩展规格选择。

constwant:Want={bundleName:DESKTOP_FORM_BUNDLE_NAME,abilityName:DESKTOP_FORM_ABILITY_NAME,parameters:{'ohos.extra.param.key.form_dimension':DESKTOP_FORM_DIMENSION_2_4,'ohos.extra.param.key.form_name':DESKTOP_FORM_NAME,'ohos.extra.param.key.module_name':DESKTOP_FORM_MODULE_NAME}};formProvider.openFormManager(want);

回流视角同样关键。详情页不是最终数据源,真正的数据源是AppDataService。详情页只负责把用户意图转成服务层动作,例如收藏、编辑、设为桌面卡片。这样编辑页保存后,详情页和桌面 Form 都可以从同一个服务层重新读取,而不是互相传复杂对象。

工程检查清单

  • setDesktopFormCard()refreshDesktopForms()openFormManager()的顺序要固定。
  • 详情页不直接操作 Form UI,只表达用户动作并交给服务层。
  • 路由参数只传 id,不传完整卡片对象。
  • 异常兜底要覆盖无卡片、系统入口失败、已有桌面卡片刷新。
  • 真实路径:CardDetailPage.etsDesktopFormService.etsRoutes.ets
http://www.jsqmd.com/news/1112289/

相关文章:

  • 抠门也是生产力!Meta用“胶水芯片”把淘汰的DDR4内存塞进现代服务器
  • 2026年国内值得关注的产业创新服务平台口碑推荐
  • REST简介
  • 大数据大一新生Python入门避坑指南
  • 匹夫细说C#:庖丁解牛迭代器,那些藏在幕后的秘密
  • Unity UI 系统知识大全
  • AI如何重塑芯片设计流程:从理论到实践的深度解析
  • EG4S20BG256 芯片详解(二)
  • JMeter接口测试实战:从入门到精通,构建自动化与性能测试框架
  • 关系型 vs 非关系型:从原理到选型,一文搞定数据库核心分类
  • 大鱼吃小鱼程序分析
  • python学习笔记留痕_列表
  • 为什么使用命令eval “$(ssh-agent -s)“启动ssh-agent而不是直接启动?(ssh-agent bash)
  • 第一单元: 在Andorid模拟器上运行应用
  • 抖音无水印下载神器:免费开源工具完整指南
  • 导师严选!2026年首选推荐的专业降AIGC网站
  • HTML5和桌面软件开发的碰撞
  • K8s NFS 存储最佳实践 — 阿里云 NAS 挂载规范与故障防御
  • 大学生数学建模全攻略:从入门到获奖
  • Windows 10/11终极指南:3种场景化方案彻底卸载Microsoft Edge浏览器
  • 终极Windows 11部署指南:MediaCreationTool.bat一键制作安装介质与绕过硬件限制
  • LTC6904与PIC18F85K22实现高精度可编程时钟方案
  • 大气层系统架构解析与配置指南
  • 低查重AI写教材大揭秘,多款工具实测助力高效教材编写!
  • Verilog静态分析技术:原理、挑战与Qihe框架实践
  • 新房入住前为什么建议做一次开荒保洁?很多人入住后才后悔知道晚了
  • MySQL零基础入门(二)
  • 难免的尴尬:代码依赖
  • 工程档案、图纸与文件资料管理进入大模型时代:从文档检索到知识图谱问答
  • 神经外科手术模拟器的实时形变建模与深度学习应用