Contenteditable允许仅使用纯文本

38

我正在尝试创建一个只接受纯文本的可编辑内容。

我想要的是监听粘贴事件,然后删除所有HTML并将其作为纯文本粘贴到可编辑内容中。

为了做到这一点,我已经尝试了两种不同的方法,基于类似问题的答案,但这两种方法都存在问题。

第一种方法: 这种方法没有使用“粘贴”侦听器,而是侦听输入(不适用于此情况),这是避免使用 Clipboard API 的解决方案。

问题: 这在Chrome上运行良好,但在Firefox和IE上不行,当您复制和粘贴HTML时,它成功地删除了HTML并仅粘贴了文本,但在继续编写文本时,插入符号始终被带到可编辑内容的开头。

function convertToPlaintext() {
  var textContent = this.textContent;
  this.textContent = textContent;
}

var contentEditableNodes = document.querySelectorAll('.plaintext[contenteditable]');

[].forEach.call(contentEditableNodes, function(div) {
  div.addEventListener("input", convertToPlaintext, false);
});

您可以在此处尝试基于以下代码: http://jsbin.com/moruseqeha/edit?html,css,js,output

第二步: 由于第一个方法失败并且仅侦听“粘贴”事件,因此我决定尝试使用Clipboard API。 问题在于,在IE上,document.execCommand(“insertHTML”,false,text); 似乎无法工作。 这适用于Chrome,Firefox(在v41和v42上测试)和Edge。

document.querySelector(".plaintext[contenteditable]").addEventListener("paste", function(e) {
  e.preventDefault();
  var text = "";
  if (e.clipboardData && e.clipboardData.getData) {
    text = e.clipboardData.getData("text/plain");
  } else if (window.clipboardData && window.clipboardData.getData) {
    text = window.clipboardData.getData("Text");
  }
  document.execCommand("insertHTML", false, text);
});

你可以在这里尝试: http://jsfiddle.net/marinagon/461uye5p/

有人能帮我找到解决这些问题的办法吗?还是有比这里介绍的更好的解决方案吗?

我知道我可以使用textarea,但我有我的理由不使用它。


1
我使用了你的第二个方法。(我建议你自己回答,并将其标记为正确。)我需要做一个修改,即在 ev.clipboardData 未设置时,还需检查 else if(ev.originalEvent.clipboardData...) - Darren Cook
3
好的解决方案!请记住,通过拖放操作,您仍然可以向您的区域添加HTML内容。 - Markus
就我的目的而言,只需禁用拖放即可。该API很晦涩,但您可以像这样做:function blockDragDrop(ev) { ev.dataTransfer.effectAllowed = 'none'; ev.dataTransfer.dropEffect = 'none'; ev.preventDefault(); return false; } el.addEventListener('dragstart', blockDragDrop); el.addEventListener('dragover', blockDragDrop); (如果需要,不要忘记提供删除事件的方法) - Kris Reeves
1
从@toremato即将删除的“答案”中: “想说你找到的解决方案有一个漏洞。我尝试将"<textarea></textarea>"粘贴到您提供的fiddle中,它会显示文本区域。我不知道是否还有其他HTML元素可以作为HTML粘贴,没有进一步检查。” - Paul Roub
此外,答案(即使是对自己的问题)应该作为答案发布,而不是作为对问题的编辑。 - Paul Roub
显示剩余2条评论
2个回答

11

清理粘贴数据的肮脏技巧。

function onpaste(e, el){
      setTimeout(function(){
            el.innerText = el.innerText;
        }, 10);
}

2
太好了!你怎么让它不围绕插入符移动? - Bart S

3

使用 textarea 元素代替 contentEditable 元素:(强调是我的)

textarea 元素表示一个多行的纯文本编辑控件,用于显示元素的原始值。

示例:

/* Auto resize height */
var textarea = document.querySelector('textarea');
(textarea.oninput = function() {
  textarea.style.height = 0;
  textarea.style.height = textarea.scrollHeight + 'px';
})();
textarea { width: 100%; }
<textarea>Hello! You can edit my content. But only plain-text!!!</textarea>


21
谢谢,但我想避免使用文本区域,因为我想要一个随着用户输入文本而自动增大/自适应的文本区域,而不需要外部依赖项,即使这些依赖项已被证明并不起作用。 - Marina
8
自适应文本框的大小可能比劫持粘贴操作更容易实现。 - Oriol
8
感谢您的回答,但我选择了问题更新中提到的解决方案。原因是为了避免用户每次输入内容时页面重绘:http://jsfiddle.net/marinagon/z1uxL23p/ - Marina
1
想说一下,你找到的解决方案有一个漏洞。我尝试将“<textarea></textarea>”粘贴到你提供的fiddle中,它显示了文本框。我不知道是否还有其他HTML元素可以作为HTML粘贴,没有进一步检查。 - toremato
@toremato 这个文本区域是由fiddle代码创建的。在文本区域中写入<textarea></textarea>不应该再创建一个文本区域。如果发生这种情况,那么你的浏览器存在严重的bug。 - Oriol
1
@Orial,它确实像toremato所写的那样显示一个文本区域,但只在Firefox中(在macOS上测试了最新的Firefox版本88.0.1)。 - Toxiro

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