Skip to content

xheditor从剪贴板粘贴图片的实现原理

2011年11月30日

xheditor是一个优秀的国产富文本编辑器,最近的(其实我也不知道有多久了)版本推出了一个粘贴剪贴板图片的功能,很是喜爱,好奇了好久,最终不住去看了下源码,基本明白了。

2016-07-29 似乎这个编辑器也很久没更新了,现在对上面这段话持保留态度,不做推荐。

首先,这个功能很新,不支持IE系列浏览器……用的是一些新的API。我手上的代码是1.1.10,所以代码行数以这个版本为准。

一点前置小知识是必备的,那就是对大部分截图软件来说,截图操作是一个把截取的图片转换成指定格式(windows自带的是bmp)然后放入剪贴板的过程。所以,要粘贴图片,核心就是读取剪贴板。

一、读取剪贴板的时机

近几年浏览器在拼标准、拼性能的时候,其实也在暗里拼安全,为了防止某个网页一打开就自动把你剪贴板的内容传网上去(IE6可以做到),现代浏览器不允许随时读写剪贴板。

浏览器为我们提供了onpaste事件(粘贴),读取剪贴板数据仅能在该事件发生时在事件处理程序中进行。因这里理解就好,所以就不贴代码。

二、图片数据

之所以IE不能粘贴图片,就在于IE没有处理二进制文件的机制,它只能处理文本。

在现代浏览器中,则有关于文件的API,这里用到的就是File Reader,主要用来处理二进制文件数据。

首先,在xheditor的第1922行,有一个cleanPaste()函数,它的作用就是读取剪贴板的数据,然后放入编辑器中,具体见代码注释。

javascript
var clipboardData,items,item;//for chrome

//ev是事件,其实大家都喜欢用e或者evt或者event
//这句主要是确定剪贴板中是否有图片
if(ev&&
	(clipboardData=ev.originalEvent.clipboardData)&&
	(items=clipboardData.items)&&
	(item=items[0])&&item.kind=='file'&&item.type.match(/^image\//i)
){
	var blob = item.getAsFile(),	//blob就是剪贴板中的二进制图片数据
		reader = new FileReader();

	//定义fileReader读取完数据后的回调
	reader.onload=function(){
		var sHtml='<img src="'+event.target.result+'">';	//result是base64编码后的图片
		//这里执行了一个将base64上报到服务器,然后将图片url从base64编码的图片数据换成上传后的图片地址
		sHtml=replaceRemoteImg(sHtml);
		_this.pasteHTML(sHtml);//这里应该是关于光标和插入代码的具体操作
	}

	reader.readAsDataURL(blob);	//用fileReader读取二进制图片,完成后会调用上面定义的回调函数
	return false;
}
var clipboardData,items,item;//for chrome

//ev是事件,其实大家都喜欢用e或者evt或者event
//这句主要是确定剪贴板中是否有图片
if(ev&&
	(clipboardData=ev.originalEvent.clipboardData)&&
	(items=clipboardData.items)&&
	(item=items[0])&&item.kind=='file'&&item.type.match(/^image\//i)
){
	var blob = item.getAsFile(),	//blob就是剪贴板中的二进制图片数据
		reader = new FileReader();

	//定义fileReader读取完数据后的回调
	reader.onload=function(){
		var sHtml='<img src="'+event.target.result+'">';	//result是base64编码后的图片
		//这里执行了一个将base64上报到服务器,然后将图片url从base64编码的图片数据换成上传后的图片地址
		sHtml=replaceRemoteImg(sHtml);
		_this.pasteHTML(sHtml);//这里应该是关于光标和插入代码的具体操作
	}

	reader.readAsDataURL(blob);	//用fileReader读取二进制图片,完成后会调用上面定义的回调函数
	return false;
}

好吧,本来还想写下中间上报到服务器的代码的,想了想觉得也没什么很特别的地方。最多是把base64数据当成普通URL上报,然后服务端再解码成图片。

嗯。就这样,当笔记了。