将 Javascript 技巧粘贴为纯文本

我有一个基于 execCommand的基本编辑器,如下所示。在 execCommand区域内粘贴文本有三种方法:

  • Ctrl + V
  • 右击-> 粘贴
  • 右击-> 以纯文本形式粘贴

我希望只允许粘贴没有任何 HTML 标记的纯文本。如何强制前两个操作粘贴“纯文本”?

可能的解决方案: 我能想到的方法是为(Ctrl + V)设置 keyup 事件的侦听器,并在粘贴之前去掉 HTML 标记。

  1. 这是最好的解决办法吗?
  2. 避免任何 HTML 标记粘贴是防弹的吗?
  3. 如何将侦听器添加到右击-> 粘贴?
118783 次浏览

Firefox 不允许你访问剪贴板数据,所以你需要做一个“黑客”让它工作。我还没有找到一个完整的解决方案,但是你可以通过创建一个 textarea 并粘贴到 ctrl + v 粘贴来修复它:

//Test if browser has the clipboard object
if (!window.Clipboard)
{
/*Create a text area element to hold your pasted text
Textarea is a good choice as it will make anything added to it in to plain text*/
var paster = document.createElement("textarea");
//Hide the textarea
paster.style.display = "none";
document.body.appendChild(paster);
//Add a new keydown event tou your editor
editor.addEventListener("keydown", function(e){


function handlePaste()
{
//Get the text from the textarea
var pastedText = paster.value;
//Move the cursor back to the editor
editor.focus();
//Check that there is a value. FF throws an error for insertHTML with an empty string
if (pastedText !== "") document.execCommand("insertHTML", false, pastedText);
//Reset the textarea
paster.value = "";
}


if (e.which === 86 && e.ctrlKey)
{
//ctrl+v => paste
//Set the focus on your textarea
paster.focus();
//We need to wait a bit, otherwise FF will still try to paste in the editor => settimeout
window.setTimeout(handlePaste, 1);
}


}, false);
}
else //Pretty much the answer given by pimvdb above
{
//Add listener for paster to force paste-as-plain-text
editor.addEventListener("paste", function(e){


//Get the plain text from the clipboard
var plain = (!!e.clipboardData)? e.clipboardData.getData("text/plain") : window.clipboardData.getData("Text");
//Stop default paste action
e.preventDefault();
//Paste plain text
document.execCommand("insertHTML", false, plain);


}, false);
}

我还在做一个纯文本粘贴,我开始讨厌所有的 ExecCommand 和 getData 错误,所以我决定用经典的方法来做,它的工作原理就像一个魔咒:

$('#editor').bind('paste', function(){
var before = document.getElementById('editor').innerHTML;
setTimeout(function(){
var after = document.getElementById('editor').innerHTML;
var pos1 = -1;
var pos2 = -1;
for (var i=0; i<after.length; i++) {
if (pos1 == -1 && before.substr(i, 1) != after.substr(i, 1)) pos1 = i;
if (pos2 == -1 && before.substr(before.length-i-1, 1) != after.substr(after.length-i-1, 1)) pos2 = i;
}
var pasted = after.substr(pos1, after.length-pos2-pos1);
var replace = pasted.replace(/<[^>]+>/g, '');
var replaced = after.substr(0, pos1)+replace+after.substr(pos1+pasted.length);
document.getElementById('editor').innerHTML = replaced;
}, 100);
});

带有我的注释的代码可以在这里找到: Http://www.albertmartin.de/blog/code.php/20/plain-text-paste-with-javascript

当然,这个问题已经得到了回答,而且这个话题已经很老了,但我想提供我的解决方案,因为它很简单,也很干净:

这在 contenteditable-div 上的粘贴事件中。

var text = '';
var that = $(this);


if (e.clipboardData)
text = e.clipboardData.getData('text/plain');
else if (window.clipboardData)
text = window.clipboardData.getData('Text');
else if (e.originalEvent.clipboardData)
text = $('<div></div>').text(e.originalEvent.clipboardData.getData('text'));


if (document.queryCommandSupported('insertText')) {
document.execCommand('insertHTML', false, $(text).html());
return false;
}
else { // IE > 7
that.find('*').each(function () {
$(this).addClass('within');
});


setTimeout(function () {
// nochmal alle durchlaufen
that.find('*').each(function () {
// wenn das element keine klasse 'within' hat, dann unwrap
// http://api.jquery.com/unwrap/
$(this).not('.within').contents().unwrap();
});
}, 1);
}

其他部分来自另一个我找不到的帖子。


更新日期: 2014年11月19日: 另一个职位

这是一个很接近的解决方案,不过它可以在 FF,Chrome 和 IE9上运行:

editor.addEventListener("paste", function(e) {
e.preventDefault();


if (e.clipboardData) {
content = (e.originalEvent || e).clipboardData.getData('text/plain');


document.execCommand('insertText', false, content);
}
else if (window.clipboardData) {
content = window.clipboardData.getData('Text');


document.selection.createRange().pasteHTML(content);
}
});

我无法在这里得到可以在 IE 下工作的公认答案,所以我做了一些调查,得到了这个可以在 IE11以及最新版本的 Chrome 和 Firefox 下工作的答案。

$('[contenteditable]').on('paste', function(e) {
e.preventDefault();
var text = '';
if (e.clipboardData || e.originalEvent.clipboardData) {
text = (e.originalEvent || e).clipboardData.getData('text/plain');
} else if (window.clipboardData) {
text = window.clipboardData.getData('Text');
}
if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, text);
} else {
document.execCommand('paste', false, text);
}
});
function PasteString() {
var editor = document.getElementById("TemplateSubPage");
editor.focus();
//  editor.select();
document.execCommand('Paste');
}


function CopyString() {
var input = document.getElementById("TemplateSubPage");
input.focus();
// input.select();
document.execCommand('Copy');
if (document.selection || document.textSelection) {
document.selection.empty();
} else if (window.getSelection) {
window.getSelection().removeAllRanges();
}
}

以上代码适用于 IE10和 IE11,现在也适用于 Chrome 和 Safari。未在 Firefox 中测试。

在 IE11中,ExecCommand 不能很好地工作 <div class="wmd-input" id="wmd-input-md" contenteditable=true> 就是我的餐具盒。

我从 window.clipboardData 中读取剪贴板数据,修改 div 的 textContent 并给出插入符号。

我给插入符号设置超时,因为如果我不设置超时,插入符号就会出现在 div 的末尾。

你应该在以下方式阅读 IE11中的剪贴板数据。如果不这样做,换行符就没有得到正确的处理,因此插入符号就会出错。

var tempDiv = document.createElement("div");
tempDiv.textContent = window.clipboardData.getData("text");
var text = tempDiv.textContent;

在 IE11和 chrome 上测试,可能在 IE9上无法工作

document.getElementById("wmd-input-md").addEventListener("paste", function (e) {
if (!e.clipboardData) {
//For IE11
e.preventDefault();
e.stopPropagation();
var tempDiv = document.createElement("div");
tempDiv.textContent = window.clipboardData.getData("text");
var text = tempDiv.textContent;
var selection = document.getSelection();
var start = selection.anchorOffset > selection.focusOffset ? selection.focusOffset : selection.anchorOffset;
var end = selection.anchorOffset > selection.focusOffset ? selection.anchorOffset : selection.focusOffset;
selection.removeAllRanges();


setTimeout(function () {
$(".wmd-input").text($(".wmd-input").text().substring(0, start)
+ text
+ $(".wmd-input").text().substring(end));
var range = document.createRange();
range.setStart(document.getElementsByClassName("wmd-input")[0].firstChild, start + text.length);
range.setEnd(document.getElementsByClassName("wmd-input")[0].firstChild, start + text.length);


selection.addRange(range);
}, 1);
} else {
//For Chrome
e.preventDefault();
var text = e.clipboardData.getData("text");


var selection = document.getSelection();
var start = selection.anchorOffset > selection.focusOffset ? selection.focusOffset : selection.anchorOffset;
var end = selection.anchorOffset > selection.focusOffset ? selection.anchorOffset : selection.focusOffset;


$(this).text($(this).text().substring(0, start)
+ text
+ $(this).text().substring(end));


var range = document.createRange();
range.setStart($(this)[0].firstChild, start + text.length);
range.setEnd($(this)[0].firstChild, start + text.length);
selection.removeAllRanges();
selection.addRange(range);
}
}, false);

所有发布的答案似乎都不能跨浏览器工作,或者解决方案过于复杂:

  • IE 不支持命令 insertText
  • 在 IE11中使用 paste命令会导致堆栈溢出错误

对我(IE11,Edge,Chrome 和 FF)有效的方法如下:

$("div[contenteditable=true]").off('paste').on('paste', function(e) {
e.preventDefault();
var text = e.originalEvent.clipboardData ? e.originalEvent.clipboardData.getData('text/plain') : window.clipboardData.getData('Text');
_insertText(text);
});


function _insertText(text) {
// use insertText command if supported
if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, text);
}
// or insert the text content at the caret's current position
// replacing eventually selected content
else {
var range = document.getSelection().getRangeAt(0);
range.deleteContents();
var textNode = document.createTextNode(text);
range.insertNode(textNode);
range.selectNodeContents(textNode);
range.collapse(false);


var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<textarea name="t1"></textarea>
<div style="border: 1px solid;" contenteditable="true">Edit me!</div>
<input />
</body>

注意,自定义粘贴处理程序只需要/用于 contenteditable节点。由于 textarea和纯 input字段根本不支持粘贴 HTML 内容,所以这里不需要做任何事情。

经过长时间的搜索和尝试,我找到了某种最佳解决方案

记住什么是重要的

// /\x0D/g return key ASCII
window.document.execCommand('insertHTML', false, text.replace('/\x0D/g', "\\n"))




and give the css style white-space: pre-line //for displaying

var contenteditable = document.querySelector('[contenteditable]')
contenteditable.addEventListener('paste', function(e){
let text = ''
contenteditable.classList.remove('empty')
e.preventDefault()
text = (e.originalEvent || e).clipboardData.getData('text/plain')
e.clipboardData.setData('text/plain', '')
window.document.execCommand('insertHTML', false, text.replace('/\x0D/g', "\\n"))// /\x0D/g return ASCII
})
#input{
width: 100%;
height: 100px;
border: 1px solid black;
white-space: pre-line;
}
<div id="input"contenteditable="true">
<p>
</p>
</div>   

好的,因为每个人都试图处理剪贴板数据,检查按键事件,并使用 ExecCommand。

我想到了这个

密码

handlePastEvent=()=>{
document.querySelector("#new-task-content-1").addEventListener("paste",function(e)
{
        

setTimeout(function(){
document.querySelector("#new-task-content-1").innerHTML=document.querySelector("#new-task-content-1").innerText.trim();
},1);
});


}
handlePastEvent();
<div contenteditable="true" id="new-task-content-1">You cann't paste HTML here</div>

在2022年,您可以使用 CSS 用户修改: read-write-plaintext-only 来存档此文件

.plain-text-only {
user-modify: read-write-plaintext-only;
-moz-user-modify: read-write-plaintext-only;
-webkit-user-modify: read-write-plaintext-only;
}


div[contenteditable] {
padding: 1rem 0.5rem;
border: 2px solid #eee;
border-radius: 4px;
margin-bottom: 2rem;
}
<div contenteditable class="plain-text-only">Can't paste HTML here</div>
<div contenteditable>HTML styled text free</div>

请注意,execCommand()已被弃用,因此请避免在生产环境中使用它:

const editor = document.querySelector('[contentEditable]')
editor.addEventListener('paste', handlePaste)


function handlePaste(e) {
e.preventDefault()


const text = (e.clipboardData || window.clipboardData).getData('text')
const selection = window.getSelection()


if (selection.rangeCount) {
selection.deleteFromDocument()
selection.getRangeAt(0).insertNode(document.createTextNode(text))
}
}
[contentEditable] {
padding: 1em;
border: 1px solid black;
}
<div contentEditable>Paste HTML here</div>

References: