案例UndoInbox / ReturnListPage / 任务UI-1809。图中的设备状态栏、IDE、HiLog 和撤销按钮都是静态设计的技术示意不是 DevEco 或真机实际运行记录。示例采用内存删除不涉及服务器审核结论。一、侧滑是动作不应直接等于不可逆删除审核材料退回清单里「清理已处理项」是非常顺手的操作。手机空间窄侧滑比在每行塞一个删除按钮舒服得多但手势也容易误触。若用户刚滑开按钮、点了一下记录立刻从数据库和服务端消失随后发现删错恢复成本会很高。更糟的是列表发生重排后靠数组下标回滚可能把另一条记录放回去。这次我没有做复杂的流程系统只把一项容易被忽略的产品约束拆出来页面先把某条记录暂时隐藏给用户五秒撤销机会时间到、页面仍有效、暂删对象没有改变时才在本地仓库里确认删除。它叫 UndoInbox任务 UI-1809。四条示例记录分别是 R-21、R-22、R-23、R-24当前暂删的是 R-22画面中应该仍有三条可见记录并出现「撤销 R-225 秒」的提示。为什么要强调内存仓库因为客户端五秒定时并不构成分布式撤销事务。没有接服务器回执、没有离线队列、没有多端同步示例最多说明页面状态怎样才不自相矛盾。真实审核系统要补服务端幂等键、操作流水、权限鉴别和恢复通道不能把一个 UI 动效夸大成数据安全保证。封面把行项向左滑出的动作与撤销入口放在一起想表达的不是「删除更快」而是「用户操作与持久提交之间有一道门」。这道门应该由业务代码维护而不能期待 ListItem 为应用自动保留撤销历史。二、用稳定 ID 表达暂删不用变动的行号ListItem 的 swipeAction 可以配置起始侧或末尾侧的划出操作区域官方文档还讨论了边缘回弹、长距离动作等行为。但组件提供的只是交互通道记录什么时候从仓库移除、是否允许撤销以及何时提交都需要开发者自行设计。这个示例只使用末尾侧按钮不开启长距离滑动即永久删除的流程。我先定义数据结构与过滤逻辑避免 UI 层直接拿 onClick 时的 index 作为删除标识。每条记录包含 id、主题和状态pendingId 则代表当前唯一等待确认的记录。暂删期间记录仍存在于原始数组只是不出现在可见列表中因此点击撤销不必猜测它原来处在哪个位置也不需要重新向接口获取完整对象。interfaceReturnRow{id:string;subject:string;kind:string;}functionvisibleReturns(rows:ReturnRow[],pendingId:string):ReturnRow[]{returnrows.filter((row:ReturnRow)row.id!pendingId);}functionhasRow(rows:ReturnRow[],id:string):boolean{returnrows.some((row:ReturnRow)row.idid);}这个纯函数有意保持朴素数据量很小直接 filter 足够真正长列表可以使用更合适的数据结构和批量渲染策略。它不负责后台提交且不会凭空创建「删除成功」回执。删除对象用 R-22 这种稳定 ID 表示正是为了防止用户删除后数组下标整体左移。未提交时保留原始行五秒结束后才从 rows 中移除是这篇文章最重要的状态边界。三、把划出按钮接入暂删状态机具体到 ArkUIList 与 ListItem 分工清楚List 承载多行ListItem 承载单行并可配置 swipeAction 的 end。我们用自定义 Builder 绘制右侧「暂移」按钮让它回调 stageRemove。列表的 key 必须使用 row.id不能使用当前展示次序否则 R-22 暂时隐藏时R-23、R-24 的节点身份也可能跟着变化。EntryComponentstruct ReturnListPage{Stateprivaterows:ReturnRow[][{id:R-21,subject:图片尺寸待修,kind:资源},{id:R-22,subject:描述字段待核,kind:文本},{id:R-23,subject:权限说明补充,kind:说明},{id:R-24,subject:截图信息检查,kind:截图}];StateprivatependingId:string;privateepoch:number0;privatetimerId:number-1;BuilderEndButton(id:string){Button(暂移).onClick(()this.stageRemove(id))}build(){Column({space:16}){Text(UndoInbox · UI-1809).fontSize(22)List(){ForEach(visibleReturns(this.rows,this.pendingId),(row:ReturnRow){ListItem(){Text(${row.id}${row.subject}).padding(18)}.swipeAction({end:{builder:(){this.EndButton(row.id)}}})},(row:ReturnRow)row.id)}.height(380)if(this.pendingId!){Button(撤销${this.pendingId}5 秒).onClick(()this.undoRemove())}}.padding(20)}}这一段省略了同组件内的 stageRemove 与 undoRemove 方法下一节补全不能把它当成无需整理即可编译的独立文件。五秒显示的是操作时窗说明并非每秒变化的倒计时。如果产品希望展示「剩余 4、3、2 秒」还需要一个单独的 UI tick不能只修改按钮文字就称完成了时间准确性。由于 ListItem 官方 API 对 Builder 配置有版本和布局限制接入时须用项目实际 SDK 检查这一写法及支持的端侧类型。开发界面图里左侧是 ReturnListPage.ets中间是暂删与回调逻辑右侧示意模拟器显示 UI-1809 的 R-21、R-23、R-24底部 HiLog 仅用[DEMO]行说明stageR-22并非设备日志导出。四、五秒撤销窗口的真正门禁在哪里仅把 R-22 从屏幕上消失还不够。用户可能先删除 R-22又马上操作 R-23页面也可能在五秒内退出旧的 timer 回调则可能迟到。最小策略是同一时间只允许一个暂删对象。新的暂删动作到来时先撤销旧动作再建立新的时窗每次状态迁移增加 epoch回调只有持有最新代际号且对象 ID 匹配时才允许提交。// 以下方法与上一段 ReturnListPage 位于同一组件。privatestageRemove(id:string):void{if(!hasRow(this.rows,id))return;this.undoRemove();// 先撤回上一个未提交动作this.pendingIdid;consttoken:numberthis.epoch;this.timerIdsetTimeout((){if(token!this.epoch||this.pendingId!id)return;this.rowsthis.rows.filter((row:ReturnRow)row.id!id);this.pendingId;this.timerId-1;},5000)asnumber;}privateundoRemove():void{this.epoch;if(this.timerId!-1)clearTimeout(this.timerId);this.timerId-1;this.pendingId;}aboutToDisappear():void{this.undoRemove();}注意这里的「提交」只删除本地 rows。页面销毁时调用 undoRemove把未完成动作撤回避免后台定时器继续操作已结束的页面。epoch 检查是为了让旧回调失去提交资格clearTimeout 则是为了及时释放计时器两者不是二选一。即使计时器已经进入任务队列仍应通过 token 再检验一次条件。真正接入远端保存时提交阶段还要变成单独的异步状态比如 submitting、confirmed、failed不能在本地 rows 变化时就写「服务器删除成功」。若服务端提交失败应提供明确恢复或重试路径。本文的 Demo 没有网络请求因此不能推出任何后台一致性结论。五、图里应该显示怎样的状态手机屏幕示意固定采用 R-22 刚被暂删、五秒窗口尚未过去的瞬间列表只显示 R-21、R-23、R-24 三条顶部任务 UI-1809、可见计数 3/4底部可以操作「撤销 R-225 秒」。R-22 并没有被永久销毁不能把这个状态标注为「已删除成功」。即便是教学图片词语精度也要维护尤其在审核类场景中。验收可以按事件顺序设计而不是对着某张截图猜测先 stageRemove(R-22)确认可见列表三条、原始数组四条五秒内 undo确认四条恢复再次暂删并等待定时器确认内存数组变成三条暂删期间切换任务应让旧 token 失效重复触发同一行不得产生两个有效提交。这里列的是建议测试清单尚未运行自动化或真机测试。六、一个看起来合理、实际上很危险的扩展有时团队会想顺手支持「离开页面后继续自动提交」。这不是简单删除 aboutToDisappear 就能做到的。前台计时器会受应用生命周期与后台调度影响设备息屏、进程回收和多端修改也会改变事实。若真的要求跨页面、跨进程的延迟提交应把待办动作记录成持久化、可重放且可撤销的任务服务端定义最终确认时刻并通过可靠队列或系统允许的后台机制处理。不能把 UI 的五秒定时器当作可靠调度器。另一个容易被忽略的是可访问性。只有侧滑才能访问删除操作对使用辅助功能的用户并不友好。正式产品应增加语义清楚的替代按钮和焦点提示让撤销操作在限定时窗内确实可触达。页面上也应说明暂删操作对谁可见、有无审计记录。Demo 只覆盖本地单会话不能替代这些产品层面的要求。七、复盘与技术依据这轮实现我希望留下三个工程判断第一手势只表达操作意图不能直接定义最终持久提交第二撤销依赖稳定 ID 和暂存状态不能依赖会变化的下标第三计时器必须同时受到页面生命周期和代际令牌保护。照这个顺序拆开以后侧滑删除的问题就不再只是「按钮好不好用」而是一件能够被明确建模和逐步验收的业务状态转换。参考文档华为官方 ListItem APIswipeAction、SwipeActionOptions、Builder 约束https://developer.huawei.com/consumer/cn/doc/doccenter-capabilities/api/ts-container-listitem 。具体版本与属性应以当前安装 SDK 的 API 参考为准。本篇示例未执行编译、真机审核、后台数据删除或远程撤销验证。