网页截图粘贴上传
在做生产作业问答平台的时候,有一个功能需求是同意用户在提问或回答时直接截图然后粘贴在编辑框中。然后提交。在开发前端时我使用的uikit,但uikit里面的htmleditor插件对图片上传支持太差,仅仅好放弃。又去看了其它网页编辑控件,但发现这些控件处理图片的方式都是选择网络上图片或者从本地上传的,这对发表文章博客之类的还好。可是对于我所做的问答平台的用户来说,他们很多其它的仅仅是直接简短的阐述自己遇到的须要主管或他人解答的问题,对格式差点儿没有要求。所以越简单越方便越好。
參考知乎的做法。发现知乎是粘贴后马上上传图片的,这样做会存在一个问题。一旦用户取消操作之后假设没有在后台对已上传的图片数据做删除的话将会产生不少垃圾数据,与其在后台做记录,还不如把问题放到前端去解决简单。所以利用html5的FormData自己想了一套解决方式:
- 当用户粘贴截图时。将截图图片数据和创建的img元素的src属性保存到两个数组DatasArray和UrlsArray中,通过下标索引进行关联。
- 用户点击提交时获取用户编辑的内容content,遍历UrlsArray中每一元素src_url,若src_url在content中。则将content中的src_url替换成uploadfile_i, i表示src_url在UrlsArray中的索引。然后在FormData中加入(uploadfile_i。DatasArray[i])键值对。
- 在后台保存图片数据DatasArray[i]后,路径为url,将content中的uploadfile_i替换成url。
- 若是更新内容,则在后台更新数据前先记录之前的图片链接preurl,若preurl不在当前提交的content中则删除该图片。
前端代码例如以下:
var imageDatas2upload = new Array();
var imageUrls2Upload = new Array();
/* 从剪切板读取图片数据,创建img元素附加到指定元素,并将图片blob数据和img的src属性保存在数组中 */
function ReadImgFromClipboard( clipboardData, containerId ){
var i = 0, items, item, types;
if( clipboardData ){
items = clipboardData.items;
if( !items ){
return;
}
// 获取数据类型
item = items[0];
types = clipboardData.types || [];
for( ; i < types.length; i++ ){
if( types[i] === 'Files' ){
item = items[i];
break;
}
}
// 推断是否是图片类型
if( item && item.kind === 'file' && item.type.match(/^image\//i) ){
// 读取二进制图片数据
var blob = item.getAsFile();
if(blob){
var reader = new FileReader();
reader.onload = function(e){
// 附加img元素到指定元素
var img = new Image();
img.src = e.target.result;
$("#"+containerId).append(img);
// 保存blob数据和src属性值到数组
imageDatas2upload.push(blob);
imageUrls2Upload.push(img.src);
};
reader.readAsDataURL(blob);
}
}
}
}
function csl_newqes(title, detail, topics, callback){
var c = new FormData;
c.append("via", "xhr2");
// 将img的src属性值替换为占位符,并向FormData中加入(占位符,数据)键值对
for(var i=0;i<imageUrls2Upload.length;i++){
if(detail.indexOf(imageUrls2Upload[i]) >= 0){
var filename = 'upload_file_' + i;
detail = detail.replace(imageUrls2Upload[i],filename);
c.append(filename, imageDatas2upload[i],filename);
}
}
c.append("detail", detail);
// 清空数据
imageUrls2Upload = [];
imageDatas2upload = [];
if(topics instanceof Array){
topics = topics.join();
}
c.append("topics", topics);
c.append("title", title);
var success_callback = callback || function(){};
$.ajax({
url : '/create-question/' ,
type : 'POST',
data : c,
processData: false, // 告知jquery不要自己主动转换数据
contentType: false, // 告知jquery不要设置Content-Type请求头
dataType : 'json',
success : function(data){
if(data.success){
success_callback(data);
}
else{
_alertErrorResponse(data.message);
}
},
error : function(xhr, ts){
var msg = ts + ' : ' + xhr.statusText;
_alertErrorResponse(msg);
}
});
}
Django后台代码例如以下:
@login_required
def create_question(request):
result = {'success':1, 'message':'', 'qid':None}
try:
title = request.POST['title']
detail = request.POST['detail']
topics = request.POST['topics'].split(',')
#读取图片数据保存,将图片链接占位符替换成真实链接
hs = Haystack(tags=('qimages',), root=settings.MEDIA_ROOT)
for fn in request.FILES:
img = request.FILES.get(fn, None)
file_name = '%s.jpeg' % str(uuid.uuid1())
hs.save(file_name, img.read())
url = _qa_image_url_prefix + file_name
detail = re.sub(re.compile(fn), url, detail)
username = request.user.username
qes = Question().setTitle(title).setDetail(detail).setAsker(username)
for tid in topics:
if tid and tid not in qes.topics:
qes.topics.append(tid)
result['qid'] = qes.save()
except Exception as ex:
result['success'] = 0
result['message'] = 'error: %s. ' % str(ex)
return JsonResponse(result)