使用JavaScript编辑文本输入并添加到撤销堆栈中是否可能?

22

有没有一种方法可以使用 JavaScript 编辑 inputtextarea 的内容,并使得更改可以通过浏览器的“撤消”命令(例如 ctrl-Z)进行撤销?

我正在尝试将字符串(例如 "Foo {0} bar")插入到所选部分中,如果用户选择了一段文本,则将所选内容插入到字符串中的 "{0}" 位置。

例如,如果 textarea 包含 "Example 1 2 3",并且光标在 "Example 1| 2 3" 处,则该函数会将值更改为 "Example 1Foo blah bar 2 3"(在这种情况下,valueIfNothingSelected 为 "blah")。如果选择了范围 "1 2",则该函数将将值更改为 "Example Foo 1 2 bar 3"。

在 Chrome 中,我测试了此功能,它确实按预期工作,但我无法使用 undo 来撤消更改。

function insertTextAtCursor(text, valueIfNothingSelected) {
    var field = $('textarea[name="task_log_description"]')[0];
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    var processedText;
    if (startPos == endPos) {
        processedText = text.replace('{0}', valueIfNothingSelected);
        field.value = field.value.substring(0, startPos) + processedText + field.value.substring(endPos, field.value.length);
        field.selectionStart = startPos + text.indexOf('{0}');
        field.selectionEnd = field.selectionStart + valueIfNothingSelected.length;
    } else {
        var selectedText = field.value.substring(startPos, endPos);
        processedText = text.replace('{0}', selectedText);
        field.value = field.value.substring(0, startPos) + processedText + field.value.substring(endPos, field.value.length);
        field.selectionStart = startPos + text.indexOf('{0}');
        field.selectionEnd = field.selectionStart + selectedText.length;
    }
    field.focus();
}

1
在我的Ubuntu 14.04上,Chrome和Firefox中的ctrl-z已经可以使用了。你遇到它无法使用的情况是什么? - Jack
@Jack 扩展问题,包括我的 JavaScript 方法。由于某种原因,当使用此方法时,“Ctrl-z”无法正常工作。 - Martin
可能是重复的问题:Javascript textarea undo redo - Fraser
3个回答

19

我在https://dev59.com/22sz5IYBdhLWcg3w8Mmr#10345596找到了一个可行的解决方案。

将 "field.value = ..." 行替换为:

document.execCommand("insertText", false, processedText);

通过将"field.focus()"移动到该行之前,我能够实现我所期望的撤销/重做功能。


不要忘记接受这个答案,因为你解决了自己的问题。这样可以避免它显示为未回答。 - GregL
我现在还需要等待两天才能接受自己的答案。 - Martin
谷歌的工作方式真有趣,这是前面的结果,不是你链接到的那个 :D - krivar
1
由于 https://bugzilla.mozilla.org/show_bug.cgi?id=1220696,这在 Firefox 中无法正常工作。 - fregante
1
https://dev59.com/xFIH5IYBdhLWcg3wNayz - Lance

3

编辑:Firefox现在也支持execCommand。你只需要这个。


这里有一个解决方案,它在Firefox中也可以工作,是最高效的,并且除了Firefox(因为本地不可能)之外,在任何地方都提供撤消功能。

// Solution
function insertText(textarea, text) {
    // https://dev59.com/2F8d5IYBdhLWcg3wQwW5#55174561
    if (!document.execCommand('insertText', false, text)) {
        textarea.setRangeText(text);
    }
}

// Demo code to add text on click
const textarea = document.querySelector('textarea');
textarea.onclick = () => insertText(
  textarea,
  '@'
);
<textarea>Click in here to add text</textarea>

我还将其打包成一个npm模块,提高了浏览器之间的一致性,并添加了"插入"、"替换"、"搜索和替换"等实用工具。


-1
这是用于替换 <textarea> 内容而不仅仅是插入的代码。
function setValueAndUpdateUndoStack(textarea, text) {
    // Must select all, so that the old text is deleted.
    textarea.focus();
    textarea.select();
    
    // https://dev59.com/2F8d5IYBdhLWcg3wQwW5#55174561
    if ( ! document.execCommand('insertText', false, text) ) {
        textarea.setRangeText(text);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接