【OpenHarmony/HarmonyOs 】ArkUI 添加与编辑复用一个弹窗:表单状态管理实战
前言
添加网站和编辑网站需要的字段基本相同,如果分别写两个弹窗,会重复布局、校验和错误提示。LinkOS 链界使用editingSiteId区分模式,让同一套表单同时完成新增与更新。本文从状态设计一直讲到提交、防重复点击和异常处理。📝
一、表单需要哪些状态
@StateshowAddDialog: boolean = false;@StateeditingSiteId: string ='';@StatesiteTitleInput: string ='';@StatesiteUrlInput: string ='';@Statesubmitting: boolean = false;@StateformError: string ='';空editingSiteId表示新增,非空表示编辑。标题和按钮文字都由这个状态派生:
Text(this.editingSiteId ?'编辑自定义网站':'添加自定义网站')Button(this.editingSiteId ?'保存':'添加')不要再额外维护isEditMode,否则两个状态可能互相矛盾。
二、打开新增模式
privateopenCreateDialog(): void {this.editingSiteId ='';this.siteTitleInput ='';this.siteUrlInput ='';this.formError ='';this.showAddDialog =true; }每次打开前重置旧值很重要。否则用户上次取消输入的内容可能出现在下一次新增中。
三、打开编辑模式并回填
privateopenEditDialog(item: UrlItem): void {this.editingSiteId = item.id;this.siteTitleInput = item.title;this.siteUrlInput = item.url;this.formError ='';this.showAddDialog =true; }页面只保存正在编辑的 ID 和表单草稿,不直接双向绑定原对象。用户点击取消时,原列表数据不会被提前修改。
四、输入控件与即时状态
TextInput({ text:this.siteTitleInput, placeholder:'网站名称'}) .onChange((value: string) => {this.siteTitleInput = value;this.formError =''; }) TextInput({ text:this.siteUrlInput, placeholder:'https://example.com'}) .onChange((value: string) => {this.siteUrlInput = value;this.formError =''; })输入阶段可以做基础提示,但最终校验必须在 Service 层再次执行,因为业务规则不能只依赖 UI。
五、统一提交函数
privateasync submitSiteForm(): Promise<void> {if(this.submitting)return;this.submitting =true;this.formError ='';constservice = EntryManageService.getInstance();try{if(this.editingSiteId) {this.customSites = await service.updateCustomSite(this.editingSiteId, { title:this.siteTitleInput, url:this.siteUrlInput } ); }else{this.customSites = await service.addCustomSite(this.siteTitleInput,this.siteUrlInput ); }this.closeSiteDialog(); }catch(error) {this.formError =this.mapSiteError(error); }finally{this.submitting =false; } }提交期间禁用按钮,可以防止连续点击创建重复数据。只有服务成功返回后才关闭弹窗;失败时保留用户输入,方便修改后重试。
六、把业务错误翻译成用户文案
Service 抛出稳定错误代码:
privatemapSiteError(error: Object): string {constmessage = `${error}`;if(message.includes('EMPTY_TITLE'))return'请输入网站名称';if(message.includes('INVALID_URL'))return'请输入有效的 HTTPS 地址';if(message.includes('DUPLICATE_URL'))return'该网站已经收藏';if(message.includes('NOT_FOUND'))return'该网站已不存在,请刷新后重试';return'保存失败,请稍后重试'; }错误最好显示在相关输入框附近。AlertDialog 更适合阻断性错误,普通表单校验使用行内文案更高效。
七、关闭时彻底清理
privatecloseSiteDialog(): void {this.showAddDialog =false;this.editingSiteId ='';this.siteTitleInput ='';this.siteUrlInput ='';this.formError =''; }遮罩关闭、取消按钮和成功提交都复用同一个关闭函数,避免某条路径忘记重置编辑 ID。
八、URL 规范化放在哪里
UI 可以提示用户输入 HTTPS,但最终规则应放在 Service:去空格、检查协议、去重、更新时间维护。这样未来从搜索建议“一键添加”时,即使不经过这个弹窗,也仍遵守同样规则。
若希望自动把example.com补成https://example.com,应明确这是业务规则,并在提交前向用户展示规范化后的地址,避免悄悄改变输入含义。
九、并发与数据过期
用户打开编辑弹窗后,该记录可能被其他设备删除。Service 更新时应按 ID 再次查询,找不到返回NOT_FOUND。云同步环境还可携带版本号,防止旧表单覆盖新修改。
十、测试清单 ✅
- 新增模式字段为空且标题正确;
- 编辑模式正确回填;
- 取消后原数据不变;
- 空标题、HTTP、重复 URL 均有准确提示;
- 连续点击只产生一次提交;
- 保存失败时输入仍保留;
- 编辑成功保留原
createdAt; - 关闭后再次打开没有旧状态。
十一、总结
复用弹窗不只是用一个三元表达式改标题。完整做法是让editingSiteId成为模式来源,表单使用独立草稿,提交统一进入 Service,成功后刷新数组,失败时保留现场,并在所有关闭路径清理状态。这套模式也能复用于分类、元服务入口和个人资料编辑。✨