修改contenteditable选中文本后Undo/Redo功能失效如何解决
问题原因
你直接修改node.nodeValue的操作属于手动修改DOM属性,不会被浏览器contenteditable的内置历史栈记录,因此原生的Ctrl+Z撤销、Ctrl+Y重做操作无法识别这类修改。
解决方案
改用浏览器原生的编辑操作接口执行内容替换即可,所有通过原生接口执行的内容修改都会自动被纳入历史管理,完全兼容原生的撤销/重做能力,不需要自己额外维护历史队列。
优化后可直接运行的代码
<div contenteditable="true" id="test" placeholder="insertText"> try to select me </div> <button id="btn">to strong</button> <script> const text = document.getElementById('test'), btn = document.getElementById('btn') // 阻止按钮点击时的默认失焦行为,保留文本选中状态 btn.addEventListener('mousedown', e => e.preventDefault()) function addNewStr(callback) { const sel = window.getSelection() // 没有选中文本直接返回 if (sel.isCollapsed) return try { const selectedText = sel.toString() if (typeof callback === 'function') { const replacement = callback(selectedText) // 调用原生插入文本命令,自动替换选中内容、自动计入历史栈 document.execCommand('insertText', false, replacement) } } catch (err) { console.log("操作失败", err) } } btn.addEventListener("click", function() { addNewStr(str => '__' + str + '__') }) </script>
方案说明
document.execCommand虽然在规范中被标记为废弃,但所有主流浏览器都保持了完整兼容,是当前处理contenteditable编辑操作成本最低、兼容性最好的方案- 原生
insertText命令会自动替换当前选中的文本,插入完成后光标会自动定位到插入内容的末尾,不需要手动计算光标位置、修改range,代码量可大幅精简 - 如果需要面向未来兼容新规范,可以改用Input Events Level 2的
beforeinput相关能力,但当前兼容性不如execCommand,需要额外做降级处理
内容的提问来源于stack exchange,提问作者JSX
相关产品推荐
相关产品推荐

