Web应用程序如何检测粘贴事件并检索要粘贴的数据?
我想在将文本粘贴到富文本编辑器之前删除HTML内容.
之后粘贴后清理文本有效,但问题是所有以前的格式都丢失了.例如,我可以在编辑器中编写一个句子并将其设为粗体,但是当我粘贴新文本时,所有格式都会丢失.我想只清理粘贴的文本,并保持以前的格式不变.
理想情况下,该解决方案应适用于所有现代浏览器(例如,MSIE,Gecko,Chrome和Safari).
请注意,MSIE有clipboardData.getData()
,但我找不到其他浏览器的类似功能.
适用于IE6 +,FF 22 +,Chrome,Safari,Edge(仅在IE9 +中测试,但适用于较低版本)
如果您需要支持粘贴HTML或Firefox <= 22,请参阅解决方案#2.
Paste
function handlePaste (e) { var clipboardData, pastedData; // Stop data actually being pasted into div e.stopPropagation(); e.preventDefault(); // Get pasted data via clipboard API clipboardData = e.clipboardData || window.clipboardData; pastedData = clipboardData.getData('Text'); // Do whatever with pasteddata alert(pastedData); } document.getElementById('editableDiv').addEventListener('paste', handlePaste);
JSFiddle:https://jsfiddle.net/swL8ftLs/12/
请注意,此解决方案使用参数"Text"作为getData
函数,这是非标准的.但是,它在撰写本文时适用于所有浏览器.
经过IE6 +,FF 3.5 +,Chrome,Safari,Edge测试
Paste
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); }
JSFiddle:https://jsfiddle.net/nicoburns/wrqmuabo/23/
说明所述onpaste
的情况下div
具有handlePaste
连接到它的功能,并通过一个参数:所述event
用于粘贴的事件对象.我们特别感兴趣的是clipboardData
此事件的属性,它允许在非浏览器中访问剪贴板.在IE中相当于window.clipboardData
,虽然这有一个稍微不同的API.
请参阅下面的资源部分
该handlepaste
函数:
这个功能有两个分支.
第一次检查event.clipboardData
是否存在并检查它的types
属性是否包含'text/html'(types
可以DOMStringList
是使用该contains
方法检查的,也可以是使用该indexOf
方法检查的字符串).如果满足所有这些条件,那么我们按照解决方案#1继续,除了'text/html'而不是'text/plain'.目前适用于Chrome和Firefox 22+.
如果不支持此方法(所有其他浏览器),那么我们
将元素的内容保存到a DocumentFragment
清空元素
调用该waitForPastedData
函数
该waitforpastedata
函数:
此函数首先轮询粘贴的数据(每20ms一次),这是必要的,因为它不会立即显示.当数据出现时:
将可编辑div(现在是粘贴数据)的innerHTML保存到变量中
恢复DocumentFragment中保存的内容
使用检索到的数据调用'processPaste'函数
该processpaste
函数:
使用粘贴的数据做任意事情.在这种情况下,我们只是提醒数据,你可以做任何你喜欢的事情.您可能希望通过某种数据清理过程运行粘贴的数据.
保存并恢复光标位置
在实际情况下,您可能希望在之前保存选择,然后将其恢复(在contentEditable
MDN粘贴事件:https://developer.mozilla.org/en-US/docs/Web/Events/paste
MSDN剪贴板:https://msdn.microsoft.com/en-us/library/ms535220(v = vs.85).aspx
MDN DocumentFragment:https://developer.mozilla.org/en/docs/Web/API/DocumentFragment
MDN DomStringList:https://developer.mozilla.org/en/docs/Web/API/DOMStringList
感谢Tim Down建议使用DocumentFragment,并且因为使用DOMStringList而不是clipData.types的字符串而在Firefox中捕获错误.
自写这个答案后情况发生了变化:现在Firefox已经在版本22中添加了支持,现在所有主流浏览器都支持在粘贴事件中访问剪贴板数据.请参阅Nico Burns的答案.
在过去,这通常不可能以跨浏览器的方式进行.理想的情况是能够通过paste
事件获取粘贴的内容,这在最近的浏览器中是可能的,但在某些较旧的浏览器中却没有(特别是Firefox <22).
当您需要支持旧版浏览器时,您可以做的就是参与其中,并且可以在Firefox 2 +,IE 5.5+和WebKit浏览器(如Safari或Chrome)中使用.TinyMCE和CKEditor的最新版本都使用这种技术:
使用按键事件处理程序检测ctrl-v/shift-ins事件
在该处理程序中,保存当前用户选择,在屏幕外添加一个textarea元素(比如左边-1000px),designMode
关闭并调用focus()
textarea,从而移动插入符并有效地重定向粘贴
在事件处理程序中设置一个非常简短的计时器(比如说1毫秒),调用另一个存储textarea值的函数,从文档中删除textarea,designMode
重新打开,恢复用户选择并粘贴文本.
请注意,这仅适用于键盘粘贴事件,而不适用于上下文或编辑菜单中的粘贴.当粘贴事件触发时,将插入符重定向到textarea(在某些浏览器中,至少)为时已晚.
如果您需要支持Firefox 2,请注意您需要将textarea放在父文档中,而不是将WYSIWYG编辑器iframe的文档放在该浏览器中.
简单版本:
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测试过.
注意:请记住检查服务器端的输入/输出(如PHP strip-tags)
现场演示
在Chrome/FF/IE11上测试过
存在Chrome/IE烦恼,即这些浏览器
我已经为Tim Downs提出了一个关于屏幕外文本的概念的一些证据.这里是代码: 只需将整个代码复制并粘贴到一个html文件中,然后尝试从文档中的任何位置粘贴(使用ctrl-v)文本. 我已经在IE9以及Firefox,Chrome和Opera的新版本中进行了测试.效果很好.也可以使用他喜欢的任何组合组合来实现这一功能.当然不要忘记包含jQuery源代码. 请随意使用此代码,如果您有一些改进或问题,请将其发回.另请注意,我不是Javascript开发人员所以我可能错过了一些东西(=>做自己的测试). 基于l2aelba anwser.这是在FF,Safari,Chrome,IE(8,9,10和11)上测试的 这个不使用任何setTimeout(). 我使用这篇伟大的文章来实现跨浏览器支持. 在粘贴之前,使用选择句柄扩展此代码:
demo 要清除粘贴的文本并使用粘贴的文本替换当前选定的文本,问题非常简单: JS: 这适用于所有支持onpaste事件和变异观察器的浏览器. 此解决方案仅比获取文本更进一步,它实际上允许您在粘贴到元素之前编辑粘贴的内容. 它的工作原理是使用contenteditable,onpaste事件(由所有主流浏览器支持)和变异观察者(由Chrome,Firefox和IE11 +支持) 步骤1 创建一个具有contenteditable的HTML元素 第2步 在您的Javascript代码中添加以下事件 我们需要绑定pasteCallBack,因为异步调用变异观察器. 第3步 将以下函数添加到您的代码中 } 代码的作用: 有人使用ctrl-v,contextmenu或其他方法触发粘贴事件 在粘贴事件中,创建了一个具有contenteditable的新元素(具有contenteditable的元素具有提升的权限) 保存目标元素的插入符号位置. 焦点设置为新元素 内容将粘贴到新元素中并在DOM中呈现. 变异观察者捕获了这个(它记录了对dom树和内容的所有更改).然后触发突变事件. 粘贴内容的dom被克隆到变量中并返回到回调.临时元素被破坏. 回调接收克隆的DOM.插入符号已恢复.您可以在将其附加到目标之前对其进行编辑.元件.在这个例子中,我使用Tim Downs函数来保存/恢复插入符并将HTML粘贴到元素中. 非常感谢Tim Down
看到这篇文章的答案: 在粘贴事件上获取有关文档的粘贴内容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: /sf/ask/17360801/ */
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;
}
5> JanM..:
e.ctrlKey或e.metaKey是JavaScript DOM的一部分,而不是jQuery:https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
或许它并不总是91:http://stackoverflow.com/questions/3834175/jquery-key-code-for-command-key无论如何,我很确定jQuery会为你处理所有这些,只需检查e.ctrlKey或e.metaKey我想.
我不认为这适用于右键单击和粘贴.很多人都采用这种方法.
6> tmorell..: $("#editText").on("paste", function (e) {
e.preventDefault();
var text;
var clp = (e.originalEvent || e).clipboardData;
if (clp === undefined || clp === null) {
text = window.clipboardData.getData("text") || "";
if (text !== "") {
if (window.getSelection) {
var newNode = document.createElement("span");
newNode.innerHTML = text;
window.getSelection().getRangeAt(0).insertNode(newNode);
} else {
document.selection.createRange().pasteHTML(text);
}
}
} else {
text = clp.getData('text/plain') || "";
if (text !== "") {
document.execCommand('insertText', false, text);
}
}
});
7> 小智..:$(document).on("focus", "input[type=text],textarea", function (e) {
var t = e.target;
if (!$(t).data("EventListenerSet")) {
//get length of field before paste
var keyup = function () {
$(this).data("lastLength", $(this).val().length);
};
$(t).data("lastLength", $(t).val().length);
//catch paste event
var paste = function () {
$(this).data("paste", 1);//Opera 11.11+
};
//process modified data, if paste occured
var func = function () {
if ($(this).data("paste")) {
alert(this.value.substr($(this).data("lastLength")));
$(this).data("paste", 0);
this.value = this.value.substr(0, $(this).data("lastLength"));
$(t).data("lastLength", $(t).val().length);
}
};
if (window.addEventListener) {
t.addEventListener('keyup', keyup, false);
t.addEventListener('paste', paste, false);
t.addEventListener('input', func, false);
}
else {//IE
t.attachEvent('onkeyup', function () {
keyup.call(t);
});
t.attachEvent('onpaste', function () {
paste.call(t);
});
t.attachEvent('onpropertychange', function () {
func.call(t);
});
}
$(t).data("EventListenerSet", 1);
}
});
8> Matt Crinkla..:function handlepaste(el, e) {
document.execCommand('insertText', false, e.clipboardData.getData('text/plain'));
e.preventDefault();
}
9> Mouser..:
document.getElementById("target_paste_element").addEventListener("paste", pasteEventVerifierEditor.bind(window, pasteCallBack), false);
function pasteEventVerifierEditor(callback, e)
{
//is fired on a paste event.
//pastes content into another contenteditable div, mutation observer observes this, content get pasted, dom tree is copied and can be referenced through call back.
//create temp div
//save the caret position.
savedCaret = saveSelection(document.getElementById("target_paste_element"));
var tempDiv = document.createElement("div");
tempDiv.id = "id_tempDiv_paste_editor";
//tempDiv.style.display = "none";
document.body.appendChild(tempDiv);
tempDiv.contentEditable = "true";
tempDiv.focus();
//we have to wait for the change to occur.
//attach a mutation observer
if (window['MutationObserver'])
{
//this is new functionality
//observer is present in firefox/chrome and IE11
// select the target node
// create an observer instance
tempDiv.observer = new MutationObserver(pasteMutationObserver.bind(window, callback));
// configuration of the observer:
var config = { attributes: false, childList: true, characterData: true, subtree: true };
// pass in the target node, as well as the observer options
tempDiv.observer.observe(tempDiv, config);
}
}
function pasteMutationObserver(callback)
{
document.getElementById("id_tempDiv_paste_editor").observer.disconnect();
delete document.getElementById("id_tempDiv_paste_editor").observer;
if (callback)
{
//return the copied dom tree to the supplied callback.
//copy to avoid closures.
callback.apply(document.getElementById("id_tempDiv_paste_editor").cloneNode(true));
}
document.body.removeChild(document.getElementById("id_tempDiv_paste_editor"));
}
function pasteCallBack()
{
//paste the content into the element.
restoreSelection(document.getElementById("target_paste_element"), savedCaret);
delete savedCaret;
pasteHtmlAtCaret(this.innerHTML, false, true);
}
saveSelection = function(containerEl) {
if (containerEl == document.activeElement)
{
var range = window.getSelection().getRangeAt(0);
var preSelectionRange = range.cloneRange();
preSelectionRange.selectNodeContents(containerEl);
preSelectionRange.setEnd(range.startContainer, range.startOffset);
var start = preSelectionRange.toString().length;
return {
start: start,
end: start + range.toString().length
};
}
};
restoreSelection = function(containerEl, savedSel) {
containerEl.focus();
var charIndex = 0, range = document.createRange();
range.setStart(containerEl, 0);
range.collapse(true);
var nodeStack = [containerEl], node, foundStart = false, stop = false;
while (!stop && (node = nodeStack.pop())) {
if (node.nodeType == 3) {
var nextCharIndex = charIndex + node.length;
if (!foundStart && savedSel.start >= charIndex && savedSel.start <= nextCharIndex) {
range.setStart(node, savedSel.start - charIndex);
foundStart = true;
}
if (foundStart && savedSel.end >= charIndex && savedSel.end <= nextCharIndex) {
range.setEnd(node, savedSel.end - charIndex);
stop = true;
}
charIndex = nextCharIndex;
} else {
var i = node.childNodes.length;
while (i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
function pasteHtmlAtCaret(html, returnInNode, selectPastedContent) {
//function written by Tim Down
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// only relatively recently standardized and is not supported in
// some browsers (IE9, for one)
var el = document.createElement("div");
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ( (node = el.firstChild) ) {
lastNode = frag.appendChild(node);
}
var firstNode = frag.firstChild;
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
if (returnInNode)
{
range.setStart(lastNode, 0); //this part is edited, set caret inside pasted node.
}
else
{
range.setStartAfter(lastNode);
}
if (selectPastedContent) {
range.setStartBefore(firstNode);
} else {
range.collapse(true);
}
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if ( (sel = document.selection) && sel.type != "Control") {
// IE < 9
var originalRange = sel.createRange();
originalRange.collapse(true);
sel.createRange().pasteHTML(html);
if (selectPastedContent) {
range = sel.createRange();
range.setEndPoint("StartToStart", originalRange);
range.select();
}
}
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有