HarmonyOS开发实战:笔友-撤销/重做(Undo/Redo)在富文本中的实现
前言在富文本编辑器中撤销/重做Undo/Redo是最基础的用户操作之一。虽然 ArkUI 的 RichEditor 不直接提供 Undo/Redo 能力但我们可以通过快照栈模式自行实现。本文将以 xiexin 的ComposePage.ets为蓝本详细剖析富文本中 Undo/Redo 的实现包括historyStack快照栈设计、pointer指针管理、onTextChange推入快照以及undo()/redo()方法实现。一、Undo/Redo 快照栈设计classUndoManager{privatehistoryStack:string[][];privatepointer:number-1;privatemaxHistory:number50;pushSnapshot(snapshot:string):void{// 清除指针后的历史this.historyStackthis.historyStack.slice(0,this.pointer1);// 推入新快照this.historyStack.push(snapshot);// 限制历史长度if(this.historyStack.lengththis.maxHistory){this.historyStack.shift();}this.pointerthis.historyStack.length-1;}undo():string|null{if(this.pointer0){this.pointer--;returnthis.historyStack[this.pointer];}returnnull;}redo():string|null{if(this.pointerthis.historyStack.length-1){this.pointer;returnthis.historyStack[this.pointer];}returnnull;}getcanUndo():boolean{returnthis.pointer0;}getcanRedo():boolean{returnthis.pointerthis.historyStack.length-1;}}二、在 ComposePage 中使用EntryComponentstruct ComposePage{privateundoManager:UndoManagernewUndoManager();aboutToAppear():void{this.undoManager.pushSnapshot(this.body);}build(){Column(){RichEditor({controller:this.editorController}).onTextChange((text:string){this.bodytext;this.undoManager.pushSnapshot(text);})// 工具栏Row({space:8}){Button(撤销).enabled(this.undoManager.canUndo).onClick((){constsnapshotthis.undoManager.undo();if(snapshot!null){this.bodysnapshot;this.editorController.setText(snapshot);}})Button(重做).enabled(this.undoManager.canRedo).onClick((){constsnapshotthis.undoManager.redo();if(snapshot!null){this.bodysnapshot;this.editorController.setText(snapshot);}})}.padding(16)}}}三、参数说明方法说明返回值pushSnapshot推入快照voidundo撤销一步string | nullredo重做一步string | nullcanUndo是否可以撤销booleancanRedo是否可以重做booleanHarmonyOS 功能实现示意图总结本文详细剖析了 xiexin 的富文本 Undo/Redo 实现重点讲解了historyStack快照栈设计、pointer指针管理、onTextChange推入快照以及undo()/redo()方法实现。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力HarmonyOS 应用开发指南https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/application-dev-guideHarmonyOS 状态管理概述https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overviewHarmonyOS 高性能编程实践https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-high-performance-programmingHarmonyOS 自定义组件https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-custom-components相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netHarmonyOS RichEditor 组件https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-components/RichEditor十一、深度实现分析11.1 核心原理本功能的核心原理基于 ArkUI 的响应式状态管理机制。当 State 或 Prop 装饰的变量发生变化时ArkUI 引擎会自动触发依赖该变量的 UI 部分重新渲染无需手动操作 DOM。11.2 数据流设计渲染错误:Mermaid 渲染失败: Parse error on line 2: ... LR A[用户交互] -- B[State 变量变化] B ----------------------^ Expecting AMP, COLON, PIPE, TESTSTR, DOWN, DEFAULT, NUM, COMMA, NODE_STRING, BRKT, MINUS, MULT, UNICODE_TEXT, got LINK_ID11.3 性能考虑避免不必要渲染使用 Watch 控制渲染时机减少嵌套深度保持组件树扁平化合理使用缓存计算结果可缓存避免重复计算十二、实际项目应用在 xiexin 项目中本功能被应用于以下场景笔友列表展示笔友通信状态和关系阶段信件卡片展示信件内容和状态标签统计页面展示写信趋势数据和统计指标Componentexportstruct ExampleComponent{Propdata:string[][];build(){Column(){ForEach(this.data,(item:string){Text(item).fontSize(14).padding(8)},(item:string)item)}}}十三、生产环境注意事项错误处理所有异步操作需要 try-catch 包围日志记录使用 hilog 记录关键操作和异常信息性能监控使用 hiTraceMeter 进行性能埋点分析内存管理及时清理定时器和监听器避免内存泄漏try{awaitthis.loadData();hilog.info(0xFF00,TAG,Data loaded successfully);}catch(err){hilog.error(0xFF00,TAG,Failed to load: %{public}s,err.message);}十四、代码审查清单Prop 变量是否已赋默认值定时器是否在 aboutToDisappear 中清理列表渲染的 keyGenerator 是否唯一且稳定条件渲染是否使用 if/else 而非 Visibility.Hidden复杂计算结果是否已缓存事件监听器是否在 aboutToDisappear 中取消注册十五、综合示例EntryComponentstruct DemoPage{Stateitems:string[][示例1,示例2,示例3];Statecount:number0;build(){Column({space:16}){Text(综合示例).fontSize(24).fontWeight(FontWeight.Bold)Text(计数:${this.count}).fontSize(16)Row({space:8}){Button(增加).onClick((){this.count})Button(减少).onClick((){if(this.count0)this.count--})Button(重置).onClick((){this.count0})}List(){ForEach(this.items,(item:string){ListItem(){Text(item).fontSize(14).padding(12)}},(item:string)item)}.height(200)}.padding(16).width(100%)}}十六、相关 API 参考API说明版本要求State组件内部状态管理API 9Prop父子单向传递API 9Link父子双向同步API 9Watch状态变化监听API 9AppStorage全局状态存储API 9PersistentStorage持久化存储API 9十七、代码规范与最佳实践17.1 命名规范组件命名使用 PascalCase如AvatarComponent、PenPalCard变量命名使用 camelCase如avatarSize、selectedIndex常量命名使用 UPPER_CASE如MAX_COUNT、DEFAULT_SIZE私有方法以下划线开头如_getAvatarColor文件命名使用 kebab-case如common-components.ets17.2 代码组织每个组件文件只包含一个 Entry 组件通用组件放在 components/ 目录下页面组件放在 pages/ 目录下常量配置放在 common/ 目录下数据模型放在 model/ 目录下十八、常见面试题Q1: State 和 Prop 的区别是什么A: State 是组件内部私有状态只能在当前组件内修改Prop 是父组件传递进来的数据在子组件中只能读取修改不会影响父组件。Q2: ForEach 的 keyGenerator 为什么重要A: keyGenerator 决定了 ForEach 进行 Diff 算法的依据。如果键值不稳定或重复会导致列表项渲染异常。十九、调试技巧使用 DevEco Profiler监控帧率和布局耗时定位卡顿根因使用 hilog打印关键日志追踪代码执行路径使用 hiTraceMeter进行性能埋点分析识别性能瓶颈使用 Watch监听状态变化调试状态更新逻辑StateWatch(onDebugChange)debugValue:string;onDebugChange():void{console.log(Value changed to:,this.debugValue);}二十、总结与最佳实践20.1 核心要点总结状态管理合理选择 State/Prop/Link/StorageProp 装饰器组件设计遵循单一职责原则保持组件聚焦性能优化大数据量使用 LazyForEach组件复用使用 Reusable代码质量编写单元测试使用 Hypium 框架样式管理使用 AppColors 设计令牌统一管理颜色20.2 避免的反模式避免在 build 函数中执行耗时操作这会阻塞 UI 渲染避免在 State 中存储大型对象会导致不必要的重渲染避免过度使用 Link 增加组件耦合优先使用 Prop避免在 aboutToAppear 中执行异步操作使用生命周期合理分配避免使用全局变量替代 StorageProp全局变量无法触发响应式更新提示以上最佳实践基于 xiexin 项目的实际开发经验总结建议在项目开发中遵守这些原则可以有效提升代码质量和开发效率。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.netHarmonyOS 应用开发指南https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/application-dev-guideHarmonyOS 状态管理概述https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-overviewHarmonyOS 高性能编程实践https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-high-performance-programmingHarmonyOS 自定义组件https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-custom-componentsHarmonyOS 组件封装https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-component-encapsulationHarmonyOS Builder 装饰器https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builderHarmonyOS 组件复用https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-reusable二十一、深度扩展阅读21.1 组件设计原则在 ArkUI 中设计组件时需要遵循以下原则单一职责每个组件只负责一个功能避免职责过多开闭原则对扩展开放对修改关闭通过参数化配置实现依赖倒置依赖抽象而非具体实现降低耦合度接口隔离使用小接口而非大接口避免冗余依赖21.2 性能优化策略使用 LazyForEach大数据量列表使用懒加载只渲染可见项组件复用使用 Reusable 装饰器复用组件减少创建销毁开销状态管理合理使用 State/Prop/Link避免不必要重渲染动画优化使用 animateTo 替代 setInterval减少 CPU 占用21.3 代码示例Componentexportstruct OptimizedComponent{Propitems:string[][];StateselectedIndex:number-1;build(){List(){LazyForEach(this.items,(item:string,index:number){ListItem(){Text(item).fontSize(16).padding(16).backgroundColor(this.selectedIndexindex?AppColors.AMBER_LIGHT:AppColors.WHITE).onClick((){this.selectedIndexindex;})}},(item:string)item)}.cachedCount(3).scrollBar(BarState.Off)}}21.4 常见问题与解决方案问题类型具体问题解决方案编译错误Prop 未赋默认值在声明时添加默认值运行时错误路由参数未定义添加空值检查性能问题列表渲染卡顿使用 LazyForEach内存泄漏定时器未清理在 aboutToDisappear 中清理状态丢失State 变量未初始化在声明时赋默认值渲染异常ForEach 键值重复使用唯一 ID 作为键值21.5 推荐实践使用 AppColors 设计令牌统一管理颜色避免硬编码色值使用 Constants.ets 集中管理常量避免魔法数字使用 DataStore 门面模式封装数据操作统一访问入口使用 Builder 提取复用 UI 片段减少重复代码使用 BuilderParam 实现组件插槽提升组件灵活性二十二、补充说明提示本文提供的代码示例基于 HarmonyOS API 12适用于 HarmonyOS 5.0 及以上版本。如果你使用的是较低版本部分 API 可能不兼容。本文所有代码均可在 xiexin 项目中找到实际应用场景建议结合 DevEco Studio 开发工具进行调试和验证如有疑问欢迎在评论区留言讨论我会及时回复更多 HarmonyOS 开发资源请参考官方文档和开发者社区22.1 扩展阅读推荐HarmonyOS 应用开发指南ArkUI 声明式开发范式状态管理详解高性能编程实践自定义组件

相关新闻

从云平台到本地部署:Dify开源AI应用平台四步搭建与核心价值解析

从云平台到本地部署:Dify开源AI应用平台四步搭建与核心价值解析

如果你已经用过“扣子”(Coze),体验过那种拖拽式构建 AI 应用或智能体的便捷,你可能会问:市面上已经有这么成熟的平台了,为什么我还要费劲去本地部署一个 Dify?这个问题背后,其实隐藏…

2026/10/15 0:21:58 阅读更多 →
NRBO优化算法在BiLSTM-多头注意力模型中的应用

NRBO优化算法在BiLSTM-多头注意力模型中的应用

1. 项目概述:当优化算法遇上深度学习分类器 在时序数据分类领域,BiLSTM(双向长短期记忆网络)结合多头注意力机制(Multi-head Attention)已经成为处理长序列依赖关系的黄金搭档。但这类复杂模型总面临一个经…

2026/10/14 16:59:26 阅读更多 →
如何3步永久激活Office:开源免费解决方案完整指南

如何3步永久激活Office:开源免费解决方案完整指南

如何3步永久激活Office:开源免费解决方案完整指南 【免费下载链接】ohook An universal Office "activation" hook with main focus of enabling full functionality of subscription editions 项目地址: https://gitcode.com/gh_mirrors/oh/ohook …

2026/10/15 5:22:33 阅读更多 →

最新新闻

Fontsource 字体解析:Amarante —— 基于 Art Nouveau 的中等对比度展示字体

Fontsource 字体解析:Amarante —— 基于 Art Nouveau 的中等对比度展示字体

前端CLI开发工具 【免费下载链接】fontsource Self-host Open Source fonts in neatly bundled NPM packages. 项目地址: https://gitcode.com/gh_mirrors/fo/fontsource 点击查看 免费下载 Amarante 是 Fontsource 注册表中收录的 Google 系字体之一,由…

2026/10/15 5:39:22 阅读更多 →
372.高通 EDL Sahara/Firehose 协议详解,安卓黑砖救砖 + 分区镜像校验实战源码

372.高通 EDL Sahara/Firehose 协议详解,安卓黑砖救砖 + 分区镜像校验实战源码

摘要 本文面向具备基础计算机操作能力的开发者与维修人员,系统性地阐述安卓设备刷机与维修的底层逻辑。文章从BootROM到Android系统的启动链路出发,深入解析Fastboot与EDL两种核心刷机协议的通信机制,结合真实变砖救援案例,提供完整的操作流程与可运行的Python自动化脚本。…

2026/10/15 5:39:22 阅读更多 →
直流偏磁下变压器励磁电流谐波分析:Simulink仿真与FFT指南

直流偏磁下变压器励磁电流谐波分析:Simulink仿真与FFT指南

简介:这份文档是重庆邮电大学自动化学院/工业互联网学院学生在“复杂电气工程系统设计”课程中完成的A等实验报告,主题聚焦直流偏磁下变压器励磁电流谐波分析。报告从地磁风暴与高压直流输电两大现实场景切入,系统阐述直流偏磁的产生机理、对…

2026/10/15 5:39:22 阅读更多 →
基于SSM的门面商铺租赁管理系统设计与实现

基于SSM的门面商铺租赁管理系统设计与实现

每年到这个时间点,总有准备毕设的同学来问:JavaWeb方向到底选什么题目,既能体现技术功底,又不至于把自己逼到绝路。如果你正在“基于SSM的门面商铺租赁管理系统”这个题目上犹豫,我直接说结论:这是一个非常…

2026/10/15 5:39:22 阅读更多 →
MutationObserver:高效监控DOM变化的现代API

MutationObserver:高效监控DOM变化的现代API

1. MutationObserver 基础解析MutationObserver 是现代浏览器提供的原生API,用于监测DOM树中的节点变化。与传统的Mutation Events相比,它具有显著的性能优势:异步触发机制避免频繁回调导致的性能问题批量处理DOM变更,减少不必要的…

2026/10/15 5:39:22 阅读更多 →
Multi-Agent系统Tracing实战:从线上事故到执行链记录体系

Multi-Agent系统Tracing实战:从线上事故到执行链记录体系

1. 从一次线上事故说起:为什么Multi-Agent系统必须做Tracing去年冬天,我们团队上线了一套基于多智能体协作的自动化内容处理系统,四个Agent分别负责信息抽取、逻辑校验、格式转换和最终输出。上线第三天,运营同学反馈说有一批文档…

2026/10/15 5:38:22 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →