Javascript 设置值后,如何使撤消在HTML文本区域中工作?

Javascript 设置值后,如何使撤消在HTML文本区域中工作?,javascript,html,textarea,preventdefault,Javascript,Html,Textarea,Preventdefault,我有一个元素,可以从中监听某些按键。就像用户键入Tab键一样,我会阻止更改焦点的默认操作,并在正确的位置添加Tab字符 问题是,当用户按下我监听的其中一个键时,“撤消”会有点失控。如何使撤消/重做功能正常工作?我曾想过监听ctrl/cmd-z和ctrl/cmd-shift-z键的按下,记录所有内容,并处理撤消/重做,但编辑和上下文菜单选项都不起作用 您可以通过使用制表符和回车键键入字母,然后尝试撤消和重做来查看: const textarea=document.querySelector('t

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

问题是,当用户按下我监听的其中一个键时,“撤消”会有点失控。如何使撤消/重做功能正常工作?我曾想过监听ctrl/cmd-z和ctrl/cmd-shift-z键的按下,记录所有内容,并处理撤消/重做,但编辑和上下文菜单选项都不起作用

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

const textarea=document.querySelector('textarea')
textarea.addEventListener('keydown',函数(事件){
如果(event.key==“Tab”){
event.preventDefault()
const cursor=textarea.selectionStart
textarea.value=textarea.value.slice(0,光标)+'\t'+textarea.value.slice(textarea.selectionEnd)
textarea.selectionStart=textarea.selectionEnd=cursor+1
}否则如果(event.key==“输入”){
event.preventDefault()
const cursor=textarea.selectionStart
textarea.value=textarea.value.slice(0,光标)+'\n'+textarea.value.slice(textarea.selectionEnd)
textarea.selectionStart=textarea.selectionEnd=cursor+1
}
})

我认为问题的核心是Javascript和浏览器默认的撤销方法之间缺乏交互。使用Javascript向文本区域添加文本不会以任何方式告知浏览器的“撤消”删除附加文本,因为浏览器的“撤消”仅用于删除用户输入的文本,而不是Javascript输入的文本

以代码为例。按下Enter键后,您会告诉eventListener preventDefault,这将阻止Enter键将用户输入附加到textarea。然后使用Javascript合成输入,浏览器的“撤消”不会跟踪该输入

您可以通过使用来克服这种缺乏交互的情况。您可以通过链接检查它的浏览器支持

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');
    }

});

当我在上面运行它时,它对我起作用了,我使用的是firefoxit对我也起作用了同样的代码,Google Crome版本59.0.3071.86(官方版本)(64位),很有趣,它对你们起作用了。我在macOS 10.12.5上的Google Chrome版本59.0.3071.86(官方版本)(64位)上总是失败。我刚在最新的Firefox上试用过,撤销/重做效果很好!我不知道在光标位置插入字符串的
document.execCommand
机制!我在Chrome59上玩过一点,
delete
有点搞笑,但总的来说,它确实能让undo/redo工作!谢谢。如果Stackoverflow的编辑器中有
选项卡
那就太棒了!事实上,
execCommand
应该可以在Firefox上运行,但是这个特定的代码片段在Firefox上不起作用(我使用的是v75.0)。这个问题是众所周知的,根据MDN,
execCommand()
现在已被弃用。从“本规范不完整,预计不会超过草案状态”(据Git称,自2015年8月7日以来就是如此)中可以看出,这里有一个相关问题没有出现在“相关”侧栏中: