html - 如何撤消对 contenteditable div 上的脚本所做的更改

标签 html editor contenteditable undo

让我们拥有 contenteditable div。浏览器本身管理其撤消。 但是,当从脚本(除了用户操作之外)进行其他内容更改(或触摸选择范围)时,它会停止按用户预期运行。

换句话说,当用户按下 Ctrl+Z 时,div 内容不会恢复到之前的状态。

参见以下简化的仿真示例:

https://codepen.io/farin/pen/WNEMVEB

const editor = document.getElementById("editor")
editor.addEventListener("keydown", ev => {  
  if (ev.key === 'a') {
    const sel = window.getSelection()
    const range = window.getSelection().getRangeAt(0)
    const node = range.startContainer;
    const value = node.nodeValue       
    node.nodeValue = value + 'aa'        
    range.setStart(node, value.length + 2)
    range.setEnd(node, value.length + 2)
    ev.preventDefault()
  }
})

所有书写的“a”字母都是双写的。

只要不输入“a”就可以撤消。 当用户输入“a”(作为双“aa”附加到文本中)并按 Ctrl+Z 时,他预计“a”将被删除并且光标移回原始位置。

相反,撤消时仅恢复一个“a”,并保留脚本添加的第二个“a”。

如果事件也被 PreventDefault() 阻止(在本示例中不需要,但在我的现实世界示例中我几乎无法避免它),那么一切都会更糟。 因为撤消会恢复之前的用户操作。

我可以想象整个撤消/重做内容将由脚本管理,但这意味着整个撤消/重做逻辑的实现。这太复杂了,可能很脆弱,而且可能有很多故障。

相反,我想告诉浏览器诸如存在原子更改之类的信息,该更改应该由一个用户撤消恢复。这可能吗?

最佳答案

您可以将“修订版本”存储在数组中,然后每当以编程方式更改 innerHTML 时,将 divinnerHTML 推送到该数组中其中。

然后,每当用户使用 Ctrl + Z 时,您都可以将 div 的 innerHTML 设置为修订数组中的最后一项快捷方式。

const previousRevisions = []

function saveState() {
  previousRevisions.push(editor.innerHTML)
}

function undoEdit() {
  if (previousRevisions.length > 0) {
    editor.innerHTML = previousRevisions.pop();
  }
}

const editor = document.getElementById("editor")

editor.addEventListener("keydown", ev => {
  if (ev.key === 'a') {
    saveState()
    const sel = window.getSelection()
    const range = window.getSelection().getRangeAt(0)
    const node = range.startContainer;
    const value = node.nodeValue
    node.nodeValue = value + 'a'
    range.setStart(node, value.length + 1)
    range.setEnd(node, value.length + 1)
  } else if (ev.ctrlKey && ev.key == 'z') {
    undoEdit()
  }
})
#editor{width:600px;min-height:250px;border:1px solid black;font-size:24px;margin:0 auto;padding:10px;font-family:monospace;word-break:break-all}
<div id="editor" contenteditable="true">type here&nbsp;</div>

此解决方案的好处是,它不会与浏览器的 native Ctrl + Z 快捷键行为发生冲突。

关于html - 如何撤消对 contenteditable div 上的脚本所做的更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69857400/

相关文章:

javascript - 尽管位于 HTML 源代码中,DOM 中的某些对象似乎并未呈现?

javascript - 触发数字键盘以在所有移动设备上输入文本

javascript - 如何将带有主题和扩展名的 ACE 编辑器存储在单个文件中?

javascript - 在 contentEditable div 中使用 jQuery 清理粘贴事件

javascript - 防止 IE 中 contenteditable div 中按钮的大小调整

html - 对齐所有类型的 html 输入

javascript - 如何使用javascript在取消选中复选框时清空文本框

c++ - 编辑文本缓冲区

editor - 程序员的 Notepad++ 替代品

javascript - contenteditable 不适用于动态生成的元素