Web应用程序如何检测粘贴事件并检索要粘贴的数据?
我想在将文本粘贴到富文本编辑器之前删除HTML内容 .
之后粘贴后清理文本有效,但问题是所有以前的格式都丢失了 . 例如,我可以在编辑器中编写一个句子并将其设为粗体,但是当我粘贴新文本时,所有格式都会丢失 . 我想只清理粘贴的文本,并保持以前的格式不变 .
理想情况下,该解决方案应适用于所有现代浏览器(例如,MSIE,Gecko,Chrome和Safari) .
请注意,MSIE有 clipboardData.getData()
,但我找不到其他浏览器的类似功能 .
20 Answers
解决方案#1(仅限纯文本,需要Firefox 22)
适用于IE6,FF 22,Chrome,Safari,Edge(仅在IE9中测试,但适用于较低版本)
如果您需要支持粘贴HTML或Firefox <= 22,请参阅解决方案#2 .
HTML
JavaScript
JSFiddle:https://jsfiddle.net/swL8ftLs/12/
请注意,此解决方案使用参数'Text'作为
getData
函数,这是非标准函数 . 但是,它在撰写本文时适用于所有浏览器 .解决方案#2(HTML并适用于Firefox <= 22)
在IE6,FF 3.5,Chrome,Safari,Edge中测试过
HTML
JavaScript
JSFiddle:https://jsfiddle.net/nicoburns/wrqmuabo/23/
解释
div
的onpaste
事件附加了handlePaste
函数并传递了一个参数:粘贴事件的event
对象 . 我们特别感兴趣的是此事件的clipboardData
属性,它可以在非ie浏览器中启用剪贴板访问 . 在IE中,等效的是window.clipboardData
,尽管它的API略有不同 .请参阅下面的资源部分
The handlepaste function:
这个功能有两个分支 .
第一个检查是否存在
event.clipboardData
并检查它的types
属性是否包含'text/html'(types
可以是使用contains
方法检查的DOMStringList
,也可以是使用indexOf
方法检查的字符串) . 如果满足所有这些条件,那么我们按照解决方案#1进行,除了使用'text/html'而不是'text/plain' . 目前适用于Chrome和Firefox 22 .如果不支持此方法(所有其他浏览器),那么我们
将元素的内容保存到
DocumentFragment
清空元素
调用
waitForPastedData
函数The waitforpastedata function:
此函数首先轮询粘贴的数据(每20ms一次),这是必要的,因为它不会立即显示 . 当数据出现时:
将可编辑div(现在是粘贴数据)的innerHTML保存到变量中
恢复DocumentFragment中保存的内容
使用检索到的数据调用'processPaste'函数
The processpaste function:
使用粘贴的数据做任意事情 . 在这种情况下,我们只是提醒数据,你可以做任何你喜欢的事 . 您可能希望通过某种数据清理过程运行粘贴的数据 .
Saving and restoring the cursor position
在实际情况中,您可能希望在之前保存选择,然后将其恢复(Set cursor position on contentEditable <div>) . 然后,您可以在用户启动粘贴操作时将粘贴的数据插入光标所在的位置 .
资源:
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中捕获错误 .
The situation has changed since writing this answer: now that Firefox has added support in version 22, all major browsers now support accessing the clipboard data in a paste event. See Nico Burns's answer for an example.
在过去,这通常不可能以跨浏览器的方式进行 . 理想情况是能够通过
paste
事件which is possible in recent browsers获取粘贴的内容,但不能在某些旧浏览器(特别是Firefox <22)中获取 .当您需要支持旧版浏览器时,您可以做的就是参与其中,并且可以在Firefox 2,IE 5.5和WebKit浏览器(如Safari或Chrome)中使用 . TinyMCE和CKEditor的最新版本都使用这种技术:
使用按键事件处理程序检测ctrl-v / shift-ins事件
在该处理程序中,保存当前用户选择,在屏幕外添加一个textarea元素(比如左边-1000px),关闭
designMode
并在textarea上调用focus()
,从而移动插入符并有效地重定向粘贴在事件处理程序中设置一个非常简短的计时器(比如说1毫秒),调用另一个存储textarea值的函数,从文档中删除textarea,重新打开
designMode
,恢复用户选择并粘贴文本 .请注意,这仅适用于键盘粘贴事件,而不适用于上下文或编辑菜单中的粘贴 . 当粘贴事件触发时,将插入符重定向到textarea(在某些浏览器中,至少)为时已晚 .
如果您需要支持Firefox 2,请注意您需要将textarea放在父文档中,而不是将WYSIWYG编辑器iframe的文档放在该浏览器中 .
这是上面发布的现有代码,但我已经为IE更新了它,错误是当选择现有文本并粘贴时不会删除所选内容 . 这已通过以下代码修复
请参阅下面的完整代码
我已经为Tim Downs提出了一个关于屏幕外文本的概念的一些证据 . 这里是代码:
只需将整个代码复制并粘贴到一个html文件中,然后尝试从文档中的任何位置粘贴(使用ctrl-v)文本 .
我已经在IE9以及Firefox,Chrome和Opera的新版本中进行了测试 . 效果很好 . 也可以使用他喜欢的任何组合组合来实现这一功能 . 当然不要忘记包含jQuery源代码 .
请随意使用此代码,如果您有一些改进或问题,请将其发回 . 另请注意,我不是Javascript开发人员所以我可能错过了一些东西(=>做自己的测试) .
基于 l2aelba anwser . 这是在FF,Safari,Chrome,IE(8,9,10和11)上测试的
这个不使用任何setTimeout() .
我使用this伟大的文章来实现跨浏览器支持 .
在粘贴之前,使用选择句柄扩展此代码:demo
首先想到的是谷歌关闭lib的粘贴处理程序http://closure-library.googlecode.com/svn/trunk/closure/goog/demos/pastehandler.html
Simple version:
Using
clipboardData
Demo : http://jsbin.com/nozifexasu/edit?js,output
Edge,Firefox,Chrome,Safari,Opera测试过 .
Note: 记得检查 server-side 的输入/输出(如PHP strip-tags)
这对于Nico的答案评论太久了我认为不再适用于Firefox(根据评论),并且在Safari上不适用于我 .
首先,您现在似乎可以直接从剪贴板中读取 . 而不是像以下代码:
使用:
因为Firefox有一个
types
字段是DOMStringList
,它没有实现test
.除非焦点位于
contenteditable=true
字段中,否则Firefox将不允许粘贴 .最后,Firefox不会允许可靠粘贴,除非焦点位于
textarea
(或者可能是输入),这不仅是contenteditable=true
而且还是:不是
display:none
不是
visibility:hidden
不是零大小
我试图隐藏文本字段,以便我可以在JS VNC模拟器上进行粘贴工作(即,它将转到远程客户端,并且实际上没有粘贴到
textarea
等) . 我发现试图隐藏上面的文本字段给出了有时工作的症状,但通常在第二次粘贴时失败(或当字段被清除以防止粘贴相同的数据两次),因为字段失去焦点并且无法正常恢复尽管focus()
. 我想出的解决方案是将它放在z-order: -1000
,使其成为display:none
,将其设为1px乘以1px,并将所有颜色设置为透明 . 呸 .在Safari上,您应用上述第二部分,即您需要
textarea
,而不是display:none
.这对我有用:
Live Demo
在Chrome / FF / IE11上测试过
存在Chrome / IE烦恼,即这些浏览器为每个新行添加
<div>
元素 . 有关于此here的帖子,可以通过将contenteditable元素设置为display:inline-block
来修复选择一些突出显示的HTML并将其粘贴到此处:
这适用于所有支持onpaste事件和变异观察器的浏览器 .
此解决方案仅比获取文本更进一步,它实际上允许您在粘贴到元素之前编辑粘贴的内容 .
它的工作原理是使用contenteditable,onpaste事件(由所有主流浏览器支持)和变异观察者(由Chrome,Firefox和IE11支持)
step 1
创建一个具有contenteditable的HTML元素
step 2
在您的Javascript代码中添加以下事件
我们需要绑定pasteCallBack,因为异步调用变异观察器 .
step 3
将以下函数添加到您的代码中
}
代码的作用:
有人使用ctrl-v,contextmenu或其他方法触发粘贴事件
在粘贴事件中,创建了一个具有contenteditable的新元素(具有contenteditable的元素具有提升的权限)
保存目标元素的插入符号位置 .
焦点设置为新元素
内容被粘贴到新元素中并在DOM中呈现 .
变异观察者捕获了这个(它记录了对dom树和内容的所有更改) . 然后触发突变事件 .
粘贴内容的dom被克隆到变量中并返回到回调 . 临时元素被破坏 .
回调接收克隆的DOM . 插入符号已恢复 . 您可以在将其附加到目标之前对其进行编辑 . 元件 . 在这个例子中,我使用Tim Downs函数来保存/恢复插入符并将HTML粘贴到元素中 .
非常感谢Tim Down看到这篇文章的答案:
Get the pasted content on document on paste event
只需让浏览器像往常一样在其内容可编辑div中粘贴,然后在粘贴之后交换用于自定义文本样式的任何span元素和文本本身 . 这似乎在Internet Explorer和我试过的其他浏览器中都可以正常工作......
此解决方案假定您正在运行 jQuery 和 you don't want text formatting in any of your content editable divs .
好的一面是,它非常简单 .
对于 cleaning the pasted text 和 replacing the currently selected text with the pasted text ,问题非常重要:
JS:
适用于我的解决方案是,如果要粘贴到文本输入,则会将事件侦听器添加到粘贴事件 . 由于粘贴事件发生在输入更改中的文本之前,因此我在on paste处理程序中创建了一个延迟函数,在其中我检查粘贴时发生的输入框中的更改:
你可以这样做:
使用此jQuery插件进行前贴后事件:
现在你可以使用这个插件;:
Explaination
首先为所有现有元素设置uid作为数据属性 .
然后比较POST PASTE事件的所有节点 . 因此,通过比较,您可以识别新插入的一个,因为它们将具有uid,然后只需从新创建的元素中删除style / class / id属性,以便您可以保留旧的格式 .
简单方案:
这个解决方案是替换html标签,它简单而且跨浏览器;检查这个jsfiddle:http://jsfiddle.net/tomwan/cbp1u2cx/1/,核心代码:
注意:你应该在背面做一些关于xss过滤器的工作,因为这个解决方案不能过滤像“<< >>”这样的字符串