昨晚fix了本博客一个剪贴复制的问题。
需求:希望在编辑博客时能够直接剪贴复制图片到文本框中,这样可以简单快捷的编写文章。
解决方法:是通过javascript来允许用户来粘贴图片到一个div中,然后再复制到文本框中。在读取event.clipboardData的时候chrome和Firefox出现了不同的行为。原因是firefox在某个版本后并不允许javascript访问剪贴板。
安全问题:
允许浏览器访问剪贴板有一定安全问题,正常浏览器可以设置。IE设置如下:
下面是综合网上的解决办法的一个实现:
HTML:
<div id='div' contenteditable='true' onpaste='handlepaste(this, event)'>Paste</div>
Javascript:
function handlepaste (elem, e) { var savedcontent = elem.innerHTML; if (e && e.clipboardData && e.clipboardData.getData) {// Webkit - get data from clipboard, put into editdiv, cleanup, then cancel event if (/text\/html/.test(e.clipboardData.types)) { elem.innerHTML = e.clipboardData.getData('text/html'); } else if (/text\/plain/.test(e.clipboardData.types)) { elem.innerHTML = e.clipboardData.getData('text/plain'); } else { elem.innerHTML = ""; } waitforpastedata(elem, savedcontent); if (e.preventDefault) { e.stopPropagation(); e.preventDefault(); } return false; } else {// Everything else - empty editdiv and allow browser to paste content into it, then cleanup elem.innerHTML = ""; waitforpastedata(elem, savedcontent); return true; } } function waitforpastedata (elem, savedcontent) { if (elem.childNodes && elem.childNodes.length > 0) { processpaste(elem, savedcontent); } else { that = { e: elem, s: savedcontent } that.callself = function () { waitforpastedata(that.e, that.s) } setTimeout(that.callself,20); } } function processpaste (elem, savedcontent) { pasteddata = elem.innerHTML; //^^Alternatively loop through dom (elem.childNodes or elem.getElementsByTagName) here elem.innerHTML = savedcontent; // Do whatever with gathered data; alert(pasteddata); }
处理粘贴的过程大体如下:
function handlepaste (elem, e) { /**** *0.先保存原先Element内容以备后用; *1.粘贴板上获取数据 *2.放到editDiv *3.清除数据 *4.结束事件 **/ //先保存原先Element内容以备后用; var savedcontent = elem.innerHTML; 如果是 (支持e.clipboardData的Webkit类型的浏览器:chrome or safari) 则{ 根据e.clipboardData.types来判断数据源类型,从而根据相应的类型处理数据。 数据可以通过e.clipboardData.getData来获取。 本例中只针对text/html 或text/plain的数据源做了处理,其他都设为空。 if (/text\/html/.test(e.clipboardData.types)) { elem.innerHTML = e.clipboardData.getData('text/html'); }else if (/text\/plain/.test(e.clipboardData.types)) { elem.innerHTML = e.clipboardData.getData('text/plain'); }else { elem.innerHTML = ""; } waitforpastedata(elem, savedcontent); 然后结束事件。 if (e.preventDefault) { e.stopPropagation(); e.preventDefault(); } } 否则 就{ //这类浏览器允许用户直接贴内容到里面(包括图片内容),但是需要时间等待处理。 elem.innerHTML = ""; waitforpastedata(elem, savedcontent); } } //需要等待粘贴的过程,因为它整个过程不是一瞬间的事,有可能花些时间,取决于粘贴内容的大小。 function waitforpastedata (elem, savedcontent) { if (elem.childNodes && elem.childNodes.length > 0) { //粘贴已结束,可以处理数据。 processpaste(elem, savedcontent); }else { //粘贴还未结束,需要继续等待。 that = { e: elem, s: savedcontent } that.callself = function () { waitforpastedata(that.e, that.s) } setTimeout(that.callself,20); } } function processpaste (elem, savedcontent) { //简单获取粘贴内容并alert,值设为原始内容 pasteddata = elem.innerHTML; elem.innerHTML = savedcontent; // Do whatever with gathered data; alert(pasteddata); }
这边贴一个复制粘贴图片的例子,需要稍作修改:
// We start by checking if the browser supports the // Clipboard object. If not, we need to create a // contenteditable element that catches all pasted data if (!window.Clipboard) { var pasteCatcher = document.createElement("div"); // Firefox allows images to be pasted into contenteditable elements pasteCatcher.setAttribute("contenteditable", ""); // We can hide the element and append it to the body, pasteCatcher.style.opacity = 0; document.body.appendChild(pasteCatcher); // as long as we make sure it is always in focus pasteCatcher.focus(); document.addEventListener("click", function() { pasteCatcher.focus(); }); } // Add the paste event listener window.addEventListener("paste", pasteHandler); /* Handle paste events */ function pasteHandler(e) { // We need to check if event.clipboardData is supported (Chrome) if (e.clipboardData) { // Get the items from the clipboard var items = e.clipboardData.items; if (items) { // Loop through all items, looking for any kind of image for (var i = 0; i < items.length; i++) { if (items[i].type.indexOf("image") !== -1) { // We need to represent the image as a file, var blob = items[i].getAsFile(); var reader = new FileReader(); reader.onload = function(event){ createImage(event.target.result); }; reader.readAsDataURL(blob); } } } // If we can't handle clipboard data directly (Firefox), // we need to read what was pasted from the contenteditable element } else { // This is a cheap trick to make sure we read the data // AFTER it has been inserted. setTimeout(checkInput, 1); } } /* Parse the input in the paste catcher element */ function checkInput() { // Store the pasted content in a variable var child = pasteCatcher.childNodes[0]; // Clear the inner html to make sure we're always // getting the latest inserted content pasteCatcher.innerHTML = ""; if (child) { // If the user pastes an image, the src attribute // will represent the image as a base64 encoded string. if (child.tagName === "IMG") { createImage(child.src); } } } /* Creates a new image from a given source */ function createImage(source) { var pastedImage = new Image(); pastedImage.onload = function() { // You now have the image! } pastedImage.src = source; pastedImage.id='screenShot'; pastedImage.className='screenShot'; $('#pasteImg').empty().append(pastedImage); }