web应用程序如何检测粘贴事件并检索要粘贴的数据?

我想在文本粘贴到富文本编辑器之前删除HTML内容。

在粘贴后清理文本是有效的,但问题是所有以前的格式都会丢失。例如,我可以在编辑器中编写一个句子并将其加粗,但当我粘贴新文本时,所有格式都会丢失。我只想清除粘贴的文本,并保留以前的任何格式不变。

理想情况下,解决方案应该可以跨所有现代浏览器(例如,MSIE、Gecko、Chrome和Safari)工作。

注意,MSIE有clipboardData.getData(),但我找不到其他浏览器的类似功能。


当前回答

解决方案,为我是添加事件监听器粘贴事件,如果你是粘贴到一个文本输入。 由于粘贴事件发生在输入中的文本更改之前,在我的on粘贴处理程序中,我创建了一个延迟函数,其中我检查输入框中发生的粘贴更改:

onPaste: function() {
    var oThis = this;
    setTimeout(function() { // Defer until onPaste() is done
        console.log('paste', oThis.input.value);
        // Manipulate pasted input
    }, 1);
}

其他回答

现场演示

在Chrome / FF / IE11上测试

有一个Chrome/IE的烦恼是这些浏览器为每一行添加<div>元素。这里有一篇关于这个的文章,它可以通过设置contentteditable元素为display:inline-block来修复

选择一些突出显示的HTML并粘贴在这里:

function onPaste(e){ var content; e.preventDefault(); if( e.clipboardData ){ content = e.clipboardData.getData('text/plain'); document.execCommand('insertText', false, content); return false; } else if( window.clipboardData ){ content = window.clipboardData.getData('Text'); if (window.getSelection) window.getSelection().getRangeAt(0).insertNode( document.createTextNode(content) ); } } /////// EVENT BINDING ///////// document.querySelector('[contenteditable]').addEventListener('paste', onPaste); [contenteditable]{ /* chroem bug: https://stackoverflow.com/a/24689420/104380 */ display:inline-block; width: calc(100% - 40px); min-height:120px; margin:10px; padding:10px; border:1px dashed green; } /* mark HTML inside the "contenteditable" (Shouldn't be any OFC!)' */ [contenteditable] *{ background-color:red; } <div contenteditable></div>

解决方案#1(纯文本,需要Firefox 22+)

适用于IE6+, FF 22+, Chrome, Safari, Edge (仅在IE9+中测试,但应该适用于较低版本)

如果您需要支持粘贴HTML或Firefox <= 22,请参阅解决方案#2。

函数handlePaste(e) { var clipboardData,粘贴数据; //停止数据实际粘贴到div e.stopPropagation (); e.preventDefault (); //通过剪贴板API获取粘贴数据 clipboardData = e.clipboardData || window.clipboardData; paste data = clipboardData.getData('Text'); //对粘贴数据做任何事情 警报(pastedData); } . getelementbyid(“editableDiv”)。addEventListener(“粘贴”,handlePaste); <div id='editableDiv' contenteditable='true'>粘贴</div>

JSFiddle

注意,这个解决方案为getData函数使用了参数“Text”,这是非标准的。但是,在编写本文时,它可以在所有浏览器中运行。


解决方案#2 (HTML和适用于Firefox <= 22)

测试在IE6+, FF 3.5+, Chrome, Safari, Edge

var editableDiv = document.getElementById('editableDiv'); function handlepaste(e) { var types, pastedData, savedContent; // Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+) if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) { // Check for 'text/html' in types list. See abligh's answer below for deatils on // why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as // Safari/Edge don't advertise HTML data even if it is available types = e.clipboardData.types; if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) { // Extract data and pass it to callback pastedData = e.clipboardData.getData('text/html'); processPaste(editableDiv, pastedData); // Stop the data from actually being pasted e.stopPropagation(); e.preventDefault(); return false; } } // Everything else: Move existing element contents to a DocumentFragment for safekeeping savedContent = document.createDocumentFragment(); while (editableDiv.childNodes.length > 0) { savedContent.appendChild(editableDiv.childNodes[0]); } // Then wait for browser to paste content into it and cleanup waitForPastedData(editableDiv, savedContent); return true; } function waitForPastedData(elem, savedContent) { // If data has been processes by browser, process it if (elem.childNodes && elem.childNodes.length > 0) { // Retrieve pasted content via innerHTML // (Alternatively loop through elem.childNodes or elem.getElementsByTagName here) var pastedData = elem.innerHTML; // Restore saved content elem.innerHTML = ""; elem.appendChild(savedContent); // Call callback processPaste(elem, pastedData); } // Else wait 20ms and try again else { setTimeout(function() { waitForPastedData(elem, savedContent) }, 20); } } function processPaste(elem, pastedData) { // Do whatever with gathered data; alert(pastedData); elem.focus(); } // Modern browsers. Note: 3rd argument is required for Firefox <= 6 if (editableDiv.addEventListener) { editableDiv.addEventListener('paste', handlepaste, false); } // IE <= 8 else { editableDiv.attachEvent('onpaste', handlepaste); } <div id='div' contenteditable='true'>Paste</div>

JSFiddle

解释

div的onpaste事件附加了handlePaste函数,并传递了一个参数:粘贴事件的事件对象。我们特别感兴趣的是这个事件的clipboardData属性,它允许在非ie浏览器中访问剪贴板。在IE中,对应的是window。clipboardData,尽管它有一个稍微不同的API。

请参阅下面的参考资料部分。


句柄粘贴函数:

这个函数有两个分支。

第一个检查事件是否存在。clipboardData和检查它的类型属性是否包含'text/html'(类型可以是使用contains方法检查的DOMStringList,也可以是使用indexOf方法检查的字符串)。如果所有这些条件都满足,那么我们继续执行解决方案#1,只是使用'text/html'而不是'text/plain'。目前Chrome和Firefox 22+都可以使用。

如果此方法不受支持(所有其他浏览器),则我们

将元素的内容保存到一个DocumentFragment中 清空元素 调用waitforpastedata函数


waitforpastedata函数:

这个函数首先轮询粘贴的数据(每20毫秒一次),这是必要的,因为它不会立即出现。当数据出现时:

保存可编辑div的innerHTML(现在是粘贴的数据)到一个变量 恢复保存在DocumentFragment中的内容 使用检索的数据调用'processPaste'函数


processpaste函数:

对粘贴的数据做任意的事情。在这种情况下,我们只是提醒数据,你可以做任何你喜欢的事情。您可能希望通过某种数据消毒过程来运行粘贴的数据。


保存并恢复光标位置

在实际情况下,您可能希望在之前保存选择,然后在之后恢复它(将光标位置设置为contentEditable <div>)。然后,您可以在用户发起粘贴操作时光标所在的位置插入粘贴的数据。

MDN资源

粘贴事件 文档片段 DomStringList

感谢Tim Down建议使用DocumentFragment,以及abligh在Firefox中捕捉由于使用DOMStringList而不是clipboardData.types的字符串而导致的错误

简单的版本:

document.querySelector('[contenteditable]').addEventListener('paste', (e) => {
    e.preventDefault();
    const text = (e.originalEvent || e).clipboardData.getData('text/plain');
    window.document.execCommand('insertText', false, text);
});

使用clipboardData

演示:http://jsbin.com/nozifexasu/edit?js,output

Edge, Firefox, Chrome, Safari, Opera测试。

机场当局:Document.execCommand()现已废弃。


注意:记住在服务器端也检查输入/输出(如PHP条带标签)

function myFunct( e ){
    e.preventDefault();

    var pastedText = undefined;
    if( window.clipboardData && window.clipboardData.getData ){
    pastedText = window.clipboardData.getData('Text');
} 
else if( e.clipboardData && e.clipboardData.getData ){
    pastedText = e.clipboardData.getData('text/plain');
}

//work with text

}
document.onpaste = myFunct;

这招对我很管用:

function onPasteMe(currentData, maxLen) {
    // validate max length of pasted text
    var totalCharacterCount = window.clipboardData.getData('Text').length;
}

<input type="text" onPaste="return onPasteMe(this, 50);" />