为什么在textarea上出现带有“粘贴”事件的重复文本?

时间:2019-10-17 16:00:56

标签: javascript html

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
    <form>
        <textarea id="source" cols="100" rows="20"></textarea>
    </form>
    <script type="text/javascript">
        var txarea = document.getElementById('source');
        txarea.addEventListener('paste', function(){
            let text = txarea.value;
            console.log(text);
            let replace_text = text.replace(/\n/g, ' ')
            console.log(replace_text);
            txarea.value = replace_text;
        });
    </script>
</body>
</html>

复制一些带有换行符\n的文本,例如

abc
ef

然后重复:Control + A + Control + V。然后您会看到每次出现越来越多的文本。

我试图添加一个debugger并检查发生了什么。但是在我step over最后一条语句之后,它变得一团糟。

怎么了?

1 个答案:

答案 0 :(得分:2)

让我们分解测试用例以及它与代码的交互方式。

  1. 用户选择文本区域中的所有文本。
  2. 用户启动“粘贴”。
  3. 粘贴之前,将触发回调。
  4. 您的回调将textarea的内容替换为新的,已修改的内容。 (用空格替换换行符。)
  5. 因为您已经用新内容完全替换了textarea的内容,所以用户的初始文本选择不再有效。 因此有效的光标位置现在位于新的替换内容的末尾。
  6. 发生粘贴,将新文本添加到textarea内容的末尾。

在第5步中,如果文本没有被修改(即,没有换行符开始),则所选内容仍然有效,并且粘贴操作将作为替换操作而不是附加操作。


认为,您要尝试的操作是这样的:

  1. 检测到用户正在尝试粘贴一些文本。
  2. 在粘贴文本之前对其进行修改。(通过用空格替换换行符。)

您可以使用paste event找出要粘贴的文本,即:

let paste = (event.clipboardData || window.clipboardData).getData('text');

但是您不希望仅使用此粘贴的信息替换textarea的内容,也不希望在结尾处附加文本。如果用户将插入号放在文本的中间,然后按ctrl + v,该怎么办?

输入document.execCommand

var txarea = document.getElementById('source');
txarea.addEventListener('paste', function(e) {
  e.preventDefault();

  let text = '';
  if (e.clipboardData || e.originalEvent.clipboardData) {
    text = (e.originalEvent || e).clipboardData.getData('text/plain');
  } else if (window.clipboardData) {
    text = window.clipboardData.getData('Text');
  }

  console.log(text);
  let replace_text = text.replace(/\n/g, ' ');
  console.log(replace_text);

  if (document.queryCommandSupported('insertText')) {
    document.execCommand('insertText', false, replace_text);
  } else {
    document.execCommand('paste', false, replace_text);
  }
});
<form>
  <textarea id="source" cols="100" rows="20"></textarea>
</form>


注意:Firefox在撰写本文时不支持textareainputbug report 1220696)上的'insertText'或'paste'命令,但它确实支持contenteditable div上的命令。