2023年末:修改textarea/input内容且保留撤销重做功能的方案
这个问题已被多次提出,但所有现有答案都使用了现已过时(即不再有效)或已废弃(即可能仍可用但随时可能失效)的API。
截至2023年末,如何在不丢失撤销/重做功能的前提下修改textarea/input/可编辑元素的文本?(无需自行实现繁琐的撤销/重做逻辑)
以下是已被提出的3种不同方案,外加一个自定义撤销缓冲区的尝试方案:
_simple()- 直接替换textarea值 - 会清空撤销缓冲区_execCommand()- 运行正常,但execCommand已被废弃_textEvent()- 完全无效,因“不可信”事件会被浏览器忽略_simpleCustom()- 与_simple()逻辑相同,但引入自定义撤销缓冲区,实现不够完善,仅在单一操作系统/浏览器环境下测试过
代码示例
JavaScript 代码
function _simple(el = textarea) { const data = getData(el); el.value = data.textStart + data.textInsert + data.textEnd; el.selectionStart = data.start + data.textInsert.length; el.selectionEnd = el.selectionStart; } function _execCommand() { const data = getData(textarea); document.execCommand("insertText", null, data.textInsert); } function _textEvent() { const data = getData(textarea); const event = document.createEvent('TextEvent'); event.initTextEvent('textInput', true, true, null, data.textInsert); textarea.dispatchEvent(event); } function getData(el) { el.focus(); return { start: el.selectionStart, end: el.selectionEnd, textStart: el.value.slice(0, el.selectionStart), textEnd: el.value.slice(el.selectionEnd), textInsert: "" + ~~(Math.random() * 10) } } const _simpleCustom = (el => { const getState = () => ({ value: el.value, start: el.selectionStart, end: el.selectionEnd }); const undoBuffer = [getState()]; const undoAdd = () => { undoBuffer[++undoIndex] = getState(); undoBuffer.length = undoIndex + 1; //确保当前状态是数组最后一项 }; const updateValue = data => { el.value = data.value; el.selectionStart = data.start; el.selectionEnd = data.end; } let undoIndex = 0; el.addEventListener("input", undoAdd); el.addEventListener("keydown", evt => { if (!evt.altKey && !evt.shiftKey && evt.ctrlKey && (evt.code === "KeyZ" || evt.code === "KeyY")) { evt.preventDefault(); undoIndex += evt.code === "KeyZ" ? -1 : 1 if (undoIndex >= undoBuffer.length) undoIndex = undoBuffer.length - 1; if (undoIndex < 0) undoIndex = 0; const data = undoBuffer[undoIndex]; if (data) updateValue(data); } }); return () => { _simple(el); undoAdd(); } })(textarea2);
HTML 代码
<ol> <li>输入一些文本</li> <li>点击按钮</li> <li>按下CTRL+Z(撤销)</li> </ol> <textarea id="textarea"></textarea> <br> <button onclick="_simple()">_simple()</button> <button onclick="_execCommand()">_execCommand()</button> <button onclick="_textEvent()">_textEvent()</button> <br> <br> <textarea id="textarea2"></textarea> <br> <button onclick="_simpleCustom()">_simpleCustom()</button>
内容的提问来源于stack exchange,提问作者vanowm
相关产品推荐
相关产品推荐

