在做生产作业问答平台的时候,有一个功能需求是允许用户在提问或回答时直接截图然后粘贴在编辑框中,然后提交。在开发前端时我使用的uikit,但uikit里面的htmleditor插件对图片上传支持太差,只好放弃。又去看了其他网页编辑控件,但发现这些控件处理图片的方式都是选择网络上图片或者从本地上传的,这对发表文章博客之类的还好,但是对于我所做的问答平台的用户来说,他们更多的只是直接简短的阐述自己遇到的需要主管或他人解答的问题,对格式几乎没有要求,所以越简单越方便越好。
参考知乎的做法,发现知乎是粘贴后立即上传图片的,这样做会存在一个问题,一旦用户取消操作之后如果没有在后台对已上传的图片数据做删除的话将会产生不少垃圾数据,与其在后台做记录,还不如把问题放到前端去解决简单,所以利用html5的FormData自己想了一套解决方案:
前端代码如下:
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;iif(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)