貌似我没有像qq邮箱之类的装知乎的插件
是用html5的新功能实现的吗?
看了@朱利安 的回答,发现我描述的不够清楚
我是用qq截图之类的工具截的图,然后图片本身是保存在剪切板里的,剪切板中保存的*不是*图片的地址
大家可以自己试一下,用qq截张图,然后在下面的编辑框里 ctrl+v 一下
回复内容:呵呵,刚发现知乎编辑器有这么强的功能,赶紧研究一下,记录如下
抓包
截个图,然后粘贴到编辑器,查看 http 包,发现有对upload.zhihu.com/upload 的请求
request 的格式是multipart/form-data; 图片的内容作为request body 的一部分一起传了过去
这里大概就能推测出基本原理了:监听粘贴 → 获取粘贴内容 → 将内容上传
搜索代码
在 rich_text_editor.js 里面搜索 /upload 字样,搜到了这么一段
this.vz = http://upload. + ak.sl + : + location.port + /upload;
估计是设置属性,那么再搜 .vz 看看哪里用到了,于是看到
function ze(a, b) {
var c = new formdata;
c.append("via", "xhr2");
c.append("upload_file", b);
var d;
d = $.ajaxsettings.xhr();
d.withcredentials = i;
var f = $.ajax({url: a.vz,data: c,processdata: l,contenttype: l,xhr: function() {
return d
},type: "post"}).done(function(a) {
啊,找到了,这里应该就是发送图片数据的地方,而且用了 formdata 这个 html5 特性
简单说就是 ajax 以前只能向服务器发送文本,而 html5 提供的 xmlhttprequest level2 现在支持发送二进制数据了,这里的 c.append("upload_file", b) 里面 b 应该就是那个图片的二进制数据
打断点
继续追踪就容易多了,只要在这个地方打个断点,然后往编辑器里面粘贴一个截图
chrome 调试工具的 call stack 就会告诉你,程序的上一步在哪里
看一看 a 对象的属性基本可以断定它是一个 event 对象,而且这里的这段 function 就是对粘贴事件的处理,为了验证,搜索一下 .rw 就会看到这样一段
a.f().addeventlistener("paste", u(this.rw, this));
确定推断无误,可以看到上面的处理函数中,通过 a.clipboarddata 就能取到剪贴板中的数据,并且可以通过 clipboarddata.types 来判断数据是不是图片。
这么高级的 api 是哪里来的呢?搜一下就知道了 clipboard api and events
可以看到这个 api 属于 w3c 的标准(当然还是草案阶段),但是不属于 html5
另外代码中的重点是这么一段
c.type.indexof("image") && (ze(b, c.getasfile()), a.preventdefault())
ze 就是上面的那个 ajax 发送函数,而通过 c.getasfile() 可以从剪贴板中获取二进制的数据
结论
通过 clipboard api 可以在用户粘贴时获知粘贴的内容,包括内容的格式(是否为图片),内容的二进制数据等等
通过 xmlhttprequest level2 可以实现将二进制数据以 ajax 的方式发送到服务器,即实现了上传功能
当然以上都需要浏览器的支持,估计ie下就悲剧了
最后,我现在迫切期待新浪微博的发布框能支持这个功能
这个和 html5 没有太大关系,网页浏览器很早就有这个标准了,不同浏览器下的实现接口略有区别。
粘贴(包括富文本、图片等各种格式的内容)是利用了 contenteditable p 的 onpaste 事件。
知乎的 javascript 源代码经过了混淆和压缩,非人类可阅读的,所以我就不扒他的代码了。
当在编辑器上执行粘贴的时候,onpaste 事件被触发,同时有一个事件参数 event,包含 clipboarddata 的属性。
简单来说,代码逻辑可能是这样的:
function onpasteevent (e) {
if (e && e.clipboarddata && e.clipboarddata.getdata)
{
if (/image/.test(e.clipboarddata.types))
{
//粘贴图片
var imagecontent = e.clipboarddata.getdata('image/xxxx');
//检测图片来源
//如果是最原始的 data,比如 qq 截图、word 里复制所产生,直接把 data 上传
//这一部分可能用了是 html5 中 http_content_disposition 上传机制
//除了 html5,非显式的 input[type="file"] 应该是无法上传文件的
//如果是 file,上传到知乎服务器
//如果是外部网站 url,后台 curl get 转移到知乎服务器
//最后生成一个知乎的 url,作为 img 标签插入到 contenteditable div 中
}
else if (/text\/plain/.test(e.clipboarddata.types)) {
//粘贴简单文本 ....
}
else
{
//....
}
if (e.preventdefault)
{
e.stoppropagation();
e.preventdefault();
}
return false;
}}
以上就是关于知乎回答问题编辑框用ctrl+v 粘贴图片是如何实现的详解的内容。