如何使用 JavaScript 将文本插入 textarea 而不弄乱编辑历史?

Posted

技术标签:

【中文标题】如何使用 JavaScript 将文本插入 textarea 而不弄乱编辑历史?【英文标题】:How to insert text into a textarea using JavaScript without messing up edit history? 【发布时间】:2016-09-25 17:49:30 【问题描述】:

基本上我想要的是,如果用户在文本区域中选择一些文本并按 ctrl + b,那么选择中的文本应该被星号包围。

所以基本上我想要的是:

1) textarea 内容:“你好,这是一些文本”

2) 用户选择一些文本并按下 ctrl + b "hello this is some text"(假设粗体部分是文本选择)

3) 所以我希望 textarea 内容为: “你好,这是一些*文本”

4) 并且如果用户按下 ctrl + z(或任何撤消操作) textarea 内容应该回到“你好,这是一些文本”

我已经尝试过How can i use javascript to insert text into a textarea? 和Insert text into textarea at cursor position (Javascript) 和类似的,但问题是在大多数浏览器执行撤消(ctrl + z)时,我希望文本返回到步骤1中的值。但这确实不会发生。我了解 *** 在其编辑器中实现了自己的撤消重做功能。但我希望不要那么复杂。 必须支持 chrome 和 safari

我正在考虑的一种方法是定位光标并发出合成键事件。我不知道它是否会起作用,是否没有问题

【问题讨论】:

【参考方案1】:

更新版本

在更改文本区域的整体值时保存用户历史记录,而不是:

textarea.value = newText;

用途:

textarea.focus();
document.execCommand('selectAll',false);

var el = document.createElement('p');
el.innerText = newText;

document.execCommand('inserthtml',false,el.innerHTML);

在我的中端游戏平台上大约需要 ~1 秒,其中包含超过 4,000 个字符的字符串,因此您必须确定这是否适合您的用例。 p>

旧版本

也许您对execCommand 很熟悉,并且想知道我们为什么不直接使用它:

textarea.focus();
document.execCommand('selectAll',false);
document.execCommand('insertText',false,newText);

在 Chromium 上 insertText 非常慢,尤其是对于较长的字符串。以超过 4,000 个字符为例,在我的游戏中期编译更新版本中使用的相同字符串需要 ~10 秒

确实也保存了用户历史记录,并且在历史记录状态之间移动仍然是可以接受的速度(~0.5 秒)。

这是否有意义,因为我会假设我在更新版本 Chromium 中明确地在后台做的事情?不,但我猜这就是 Chromium 今天的位置。如果旧版本变得更好,请在下方评论。

一般说明

不幸的是,execCommand 在 Firefox 的 textarea 元素中不起作用。 This may be fixed in an upcoming version.

在 Chromium 和 Firefox 中测试。

如果我找到更快的解决方案(和/或适用于 Firefox 的解决方案),我一定会分享。

【讨论】:

有趣,如果你使用insertHTML而不是insertText,它运行得更快。但是,如果有任何内容可以被读取为 HTML,它将被删除。我会做进一步的测试。 我也经历过 execCommand("insertText") 使用 Chrome(不是使用 Firefox)非常慢(我使用 contenteditable pre)。您的解决方案使它变得更好。那么瓶颈就是el.innerText = newText。使用el.appendChild(document.createTextNode(newText)) 可以加快这一速度【参考方案2】:

以下代码来自:http://www.javascriptsource.com/forms/undo-redo.html,您也可以查看其工作示例。 虽然您可能需要实现自己的功能,例如粗体、斜体等。

function iObject() 
  this.i;
  return this;


var myObject=new iObject();
myObject.i=0;
var myObject2=new iObject();
myObject2.i=0;
store_text=new Array();

//store_text[0] store initial textarea value
store_text[0]="";

function countclik(tag) 
  myObject.i++;
  var y=myObject.i;
  var x=tag.value;
  store_text[y]=x;


function undo(tag) 
  if ((myObject2.i)<(myObject.i)) 
    myObject2.i++;
   else 
    alert("Finish Undo Action");
  
  var z=store_text.length;
  z=z-myObject2.i;
  if (store_text[z]) 
  	tag.value=store_text[z];
   else 
  	tag.value=store_text[0];
  


function redo(tag) 
  if((myObject2.i)>1) 
    myObject2.i--;
   else 
    alert("Finish Redo Action");
  
  var z=store_text.length;
  z=z-myObject2.i;
  if (store_text[z]) 
    tag.value=store_text[z];
   else 
  tag.value=store_text[0];
  
 
<form name=form1>
  <input type="button"  class="red" value="Undo" onmousedown="undo(document.form1.text1);">
  <input type="button" class="red" value="Redo" onmousedown="redo(document.form1.text1);">
  <br>
  <textarea rows=7 cols=50  name=text1 onkeydown="countclik(document.form1.text1);" >
  </textarea>
</form>


<p><center>
<font face="arial, helvetica" size"-2">Free JavaScripts provided<br>
by <a href="http://javascriptsource.com">The JavaScript Source</a></font>
</center><p>

我过去使用过ckeditor,建议使用它。你也可以使用niceditor

【讨论】:

非常感谢您的回答 :) 。但正如我在问题中提到的那样,我希望在不求助于构建自己的撤消重做功能的情况下做到这一点:) 你可以使用 ckeditor 之类的插件,我相信在添加功能时它会减少你的很多工作:)

以上是关于如何使用 JavaScript 将文本插入 textarea 而不弄乱编辑历史?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JavaScript 在 HTML 文档中插入文本?

复选框使用 Javascript 将文本插入文本区域

使用 javascript 将文本插入 textarea 以用于 google chrome 扩展

如何在htmlText文本框光标处插入字符

Tex家族关系

Boostnote for Mac——如何使用TeX精美地编写数学公式