知乎回答问题编辑框用 Ctrl+V 粘贴图片是如何实现的?

貌似我没有像QQ邮箱之类的装知乎的插件 是用HTML5的新功能实现的吗? 看了@朱利安 的回答,发现我描述的不够清楚 我是用QQ截图之类的工具截的图,…
关注者
496
被浏览
133,457
登录后你可以
不限量看优质回答 私信答主深度交流 精彩内容一键收藏

@葛亮 @Dion

的启发下,继续挖掘了一下。收获如下:

在IE和Firefox下,利用html5全局属性 contenteditable 来实现根据uri粘贴一幅图像。

在Chrome下,利用特有的 clipboardData.items接口 和 getAsFile方法实现增强的粘贴图像功能(其实是从剪贴板上传的功能)。

细说如下:

一个HTML5全局属性:

contenteditable 使相应元素在页面呈现 可编辑/不可编辑 状态

see

HTML 5 全局 contenteditable 属性

<div contenteditable="true"></div>

一个推测(尚未严格验证,请知者指教):

复制一幅图片到系统粘贴板中 会有以下内容在剪贴板中生成(可能缺少某些项):

来源(类似 src ),标题(类似title),内容(可以是二进制的)

根据这三项的有无和可访问性,我们考虑以下三种剪贴板图像(获取方式下详):

type 1 . public_uri/local_img(hvae src, title, content; local can access; )

type 2 . private_uri(have src, title, content; local can not access; )

type 3 . print_screen(have content; no src, title; local can access; )

对于前面提到的<div contenteditable="true"></div> 元素而言:

不同浏览器会以不同的行为响应onpaste事件。

试验之。

代码如下:

<html>
    <title>test contenteditable</title>
  </head>
    <h2>test contenteditable</h2>
    <div contenteditable="true">paste img here</div>
    </body>
</html>

将上面的代码存储为一个html文件,然后用不同的浏览器打开。

分别用如下方式获取type1 type2 type3 三张图片:

type 1. 在你的知乎头像上点击鼠标右键,复制图片;

type 2. 用QQ截图,然后在截图上点击鼠标右键,复制;

type 3. press PrtSc/SysRq;

然后用Ctrl+V的方式将剪贴板内容粘贴到页面的DIV里面。

看到如下现象:

IE8:

type 1, 将一个 IMG标签写入DIV,并设置相应的属性,如 src, title。页面上会显示出这幅图像,真实数据是从src指定的uri读取的。

type 2, 同1,但是由于没有URI的访问权限,页面上会显示为一个无法显示的图像。

type 3, 由于没有 src, titile等内容,不会生成IMG元素,所以粘贴没有任何效果 (注意:这只是IE的行为,其他浏览器可能有不同的行为,下详)

FireFox24:

type 1, 同IE

type 2, 同IE

type 3, 虽然没有src, title。但是有content在。firefox还是会生成一个IMG标签。

标签的title等属性为空,src属性为图片的数据内容,如

<img src="data:image/png;base64,iVBOR(略去n字符)ErkJggg==" />


Chrome31:

type 1, 同IE

type 2, 同IE

type 3, 同IE

再来看一下知乎编辑框的粘贴情况,同样用上面三种粘贴板图像来测试:

IE : 同上(1 ok, with origion url; 2 not ok, with origion url; 3 not ok, no response)

FF : 同上(1 ok, with origion url; 2 not ok, with origion url; 3 ok, with data in src)

Chrome :

type 1 (ok, with new url ) !

type 2 (ok, with new url ) !! ( 图中是一张qq截图 )

type 3 (ok, with new url ) !!

全都是new uri,并且是指向知乎的服务器的,说明图片已经从剪贴板上传到服务器上了。

看来知乎的编辑框针对chrome 有特殊处理,或者说chrome提供了对粘贴板图片进行特殊处理的途径。

参考了

Paste Image From Clipboard With Javascript and MooTools

后,得到如下信息:

chrome提供了访问粘贴板中二进制数据的接口(clipboardData.items),并提供了将其转换为文件的方法(getAsFile)。

demo 如下(里面用到的图像请自行替换):

<html>
	<title>test chrome paste image</title>
<style>
	DIV#editable {
		width: 400px;
		height: 300px;
		border: 1px dashed blue;
</style>
<script type="text/javascript">
window.onload=function() {
	function paste_img(e) {
		if ( e.clipboardData.items ) {
		// google-chrome 
			alert('support clipboardData.items(chrome ...)');
			ele = e.clipboardData.items
			for (var i = 0; i < ele.length; ++i) {
				if ( ele[i].kind == 'file' && ele[i].type.indexOf('image/') !== -1 ) {
					var blob = ele[i].getAsFile();
					window.URL = window.URL || window.webkitURL;
					var blobUrl = window.URL.createObjectURL(blob);
					console.log(blobUrl);
					var new_img= document.createElement('img');
					new_img.setAttribute('src', blobUrl);
					var new_img_intro = document.createElement('p');
					new_img_intro.innerHTML = 'the pasted img url(open it in new tab): <br /><a target="_blank" href="' + blobUrl + '">' + blobUrl + '</a>';
					document.getElementById('editable').appendChild(new_img);
					document.getElementById('editable').appendChild(new_img_intro);
		} else {
			alert('non-chrome');
	document.getElementById('editable').onpaste=function(){paste_img(event);return false;};
</script>
</head>
	<h2>test image paste in browser</h2>
	<div id="non-editable" >
		<p>copy the following img, then paste it into the area below</p>
		<img src="./128.png" />
	</div>
	<div id="editable" contenteditable="true" >