设置值后如何在 HTML textarea 中进行撤消?

How to make undo work in an HTML textarea after setting the value?

我有一个 <textarea> 元素,我从中监听某些按键。就像用户键入 Tab 键一样,我会阻止更改焦点的默认操作,并在正确的位置添加制表符。

问题是当用户按下我正在监听的其中一个键时,撤消操作有点失控。如何让 undo/redo 功能发挥作用?我考虑过监听 ctrl/cmd-z 和 ctrl/cmd-shift-z 按键,记录所有内容,并处理 undos/redos,但是编辑和上下文菜单选项将不起作用...

您可以通过使用制表符和回车键输入字母然后尝试撤消和重做来查看:

const textarea = document.querySelector('textarea')
textarea.addEventListener('keydown', function (event) {
  if (event.key == "Tab") {
    event.preventDefault()
    const cursor = textarea.selectionStart
    textarea.value = textarea.value.slice(0, cursor) + '\t' + textarea.value.slice(textarea.selectionEnd)
    textarea.selectionStart = textarea.selectionEnd = cursor + 1
  } else if (event.key == "Enter") {
    event.preventDefault()
    const cursor = textarea.selectionStart
    textarea.value = textarea.value.slice(0, cursor) + '\n' + textarea.value.slice(textarea.selectionEnd)
    textarea.selectionStart = textarea.selectionEnd = cursor + 1
  }
})
<textarea cols="50" rows="20"></textarea>

我认为问题的核心是 Javascript 与浏览器的默认撤消方法之间缺乏交互。使用 Javascript 将文本附加到文本区域不会以任何方式告诉浏览器的 "undo" 删除附加的文本,因为浏览器的 "undo" 仅用于删除用户输入的文本,而不是文本Javascript输入。

以你的代码为例。按下 Enter 后,您告诉 eventListener preventDefault,这将一起阻止 Enter 键将用户输入附加到文本区域。然后,您使用 Javascript 合成输入,浏览器的 "undo" 不会跟踪该输入。

您可以使用 Document.execCommand() 来克服缺乏互动的问题。您可以通过 link.

检查它的浏览器支持
const textarea = document.querySelector('textarea');
textarea.addEventListener('keydown', function (event) {
    const cursor = textarea.selectionStart;
    if(event.key == "Tab"){
        event.preventDefault();
        document.execCommand("insertText", false, '\t');//appends a tab and makes the browser's default undo/redo aware and automatically moves cursor
    } else if (event.key == "Enter") {
        event.preventDefault();
        document.execCommand("insertText", false, '\n');
    }

});