HTML项目实战怎么实现带有历史记录栈的富文本编辑器底座

风芳酱_9059

风芳酱_9059

2026-08-28

564人浏览

原创

可编辑区域的可靠撤销重做需自建双栈机制:undostack存操作后快照,redostack存被撤操作;监听keydown、input(防抖)、paste及工具栏命令触发快照,标准化html并限长;同步保存与恢复光标位置。

html项目实战怎么实现带有历史记录栈的富文本编辑器底座

直接用 contenteditable 搭个可编辑区域只是起点,真正能回退、重做、不丢光标、不崩结构的“底座”,必须自己搭历史栈 + 状态快照机制。它不是加个 undo/redo 按钮就行,而是要从数据结构、触发时机、内存控制三方面稳住。

核心:用双栈管理编辑状态

撤销(undo)和重做(redo)本质是两个独立的栈,互不干扰:

  • undoStack 存每次操作后的完整状态(推荐初学者用 HTML 字符串快照)
  • redoStack 存被撤销的操作,供重做时还原
  • 每次有效编辑(输入、删除、格式化、粘贴)后,把当前编辑区 innerHTML 推入 undoStack,同时清空 redoStack
  • 点击撤销 → 从 undoStack 弹出一个状态 → 渲染到编辑区 → 把该状态推入 redoStack
  • 点击重做 → 从 redoStack 弹出 → 渲染 → 推入 undoStack

关键触发点:哪些操作才算“一次变更”?

不能等 input 事件才存快照——它漏掉格式操作、快捷键、粘贴等;也不能每敲一个字就存——性能爆炸。应监听并聚合以下真实变更源:

Pptx To Html
Pptx To Html

使用 MinerU 将 PowerPoint (.pptx) 演示文稿转换为 HTML,保留幻灯片内容与结构,生成可直接在网页使用的 HTML格式。

下载
  • keydown 中拦截 Ctrl+Z/Ctrl+Y,手动调用撤销/重做逻辑
  • input 事件(仅用于纯文本增删,需防抖,比如 300ms 内连续输入只记一次)
  • paste 事件:调用 preventDefault() 后清洗粘贴内容,再插入,之后立刻存快照
  • 所有工具栏命令(如加粗、列表、对齐)执行完 DOM 修改后,立即保存快照
  • 避免在 focus、blur 或鼠标移动中触发,它们不产生实质内容变更

快照怎么存才靠谱又省内存?

全量快照最简单,但要注意三点:

  • 存之前先标准化 HTML:移除空 <span></span>、清理 Word 留下的 style="mso-xxx"、把 <b></b> 统一转 <strong></strong>、删多余 <br>
  • 限制栈长度(如最多存 50 步),老记录自动踢出,防止内存溢出
  • 不要直接存 editor.innerHTML —— 它可能含浏览器自动生成的不可控标签(如 Safari 插入 <div> 而非 <code><p></p>)。建议用递归遍历节点后序列化成干净结构
  • 若需更高阶能力(如合并连续输入为一步),可改用增量变更记录,但需额外实现反向操作逻辑,初版不建议
  • 光标与状态同步不能断

    恢复快照后,光标会丢失或跳位。必须在存快照时一并记录光标位置,并在还原时恢复:

    • 存快照前,用 getSelection() + range.cloneRange() 获取当前选区起止位置(注意跨浏览器兼容性)
    • 把 range 的 startOffset、endOffset 和对应节点路径(如第几个子节点)一起存入快照对象
    • 还原快照后,重建 range 并调用 selection.removeAllRanges() → selection.addRange(range)
    • 若选区为空(如光标在段首),至少保留光标所在节点和偏移量,用 range.setStart(node, offset) 恢复

前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!

相关专题

更多
python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2103

5

前端如何实现即时通讯
前端如何实现即时通讯

实现即时通讯的方法有WebSocket、Long Polling、Server-Sent Events、WebRTC等等。详细介绍:1、WebSocket,它可以在客户端和服务器之间建立持久连接,实现实时的双向通信,前端可以使用 WebSocket API来创建WebSocket连接,并通过发送和接收消息来实现即时通讯;2、Long Polling,是一种模拟实时通信的技术等等。

2023.10.09

4483

6

前端和后端的区别
前端和后端的区别

前端关注的是用户界面的设计和交互,而后端则注重数据处理和逻辑控制。想了解更多前端后端的相关内容,可以阅读本专题下面的文章。

2024.03.19

5630

13

php和前端的关联介绍
php和前端的关联介绍

php既可以作为前端语言,也可以作为后端语言。想了解更多php和前端的相关内容,可以阅读本专题下面的文章。

2024.03.22

5078

10

前端外包工作内容有哪些
前端外包工作内容有哪些

前端外包工作内容包括:1. 网站和应用程序开发;2. 用户界面和交互设计;3. 用户体验优化;4. 设计和视觉开发;5. 跨浏览器兼容性;6. 性能优化;7. 维护和更新;8. 项目管理和沟通。想了解更多前端的相关内容,可以阅读本专题下面的文章。

2024.05.22

723

5

js获取数组长度的方法
js获取数组长度的方法

在js中,可以利用array对象的length属性来获取数组长度,该属性可设置或返回数组中元素的数目,只需要使用“array.length”语句即可返回表示数组对象的元素个数的数值,也就是长度值。php中文网还提供JavaScript数组的相关下载、相关课程等内容,供大家免费下载使用。

2023.06.20

4206

5

js刷新当前页面
js刷新当前页面

js刷新当前页面的方法:1、reload方法,该方法强迫浏览器刷新当前页面,语法为“location.reload([bForceGet]) ”;2、replace方法,该方法通过指定URL替换当前缓存在历史里(客户端)的项目,因此当使用replace方法之后,不能通过“前进”和“后退”来访问已经被替换的URL,语法为“location.replace(URL) ”。php中文网为大家带来了js刷新当前页面的相关知识、以及相关文章等内容

2023.07.04

1069

3

js四舍五入
js四舍五入

js四舍五入的方法:1、tofixed方法,可把 Number 四舍五入为指定小数位数的数字;2、round() 方法,可把一个数字舍入为最接近的整数。php中文网为大家带来了js四舍五入的相关知识、以及相关文章等内容

2023.07.04

4104

6

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

2023.09.01

840

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
GDB 17.2 官方文档集合
GDB 17.2 官方文档集合

共0课时 | 0人学习

Bootstrap 入门安装配置
Bootstrap 入门安装配置

共0课时 | 0人学习

38+ PhpStorm 提示和技巧
38+ PhpStorm 提示和技巧

共1课时 | 209人学习