昨晚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);
}