如今现代的浏览器已经有很多支持拖拽文件读取操作,其优点不再复述。前端时间利用拖拽改进了一下网站的头像上传流程,对其中的要点和实践体会做一点总结。
先看一下总体视图:
1、 文件拖拽接受区域要有明显的标示,并且要尽可能的大(由于版面的原因,这个界面的拖放盒子并不大)。可以用虚线框盒子等样式吸引用户拖拽文件。最好有明显的文字提示和图标配合。
2、 在交互体验上当文件拖入浏览器窗口时,可以用拖放区变换背景颜色等向用户发起放置操作邀请。
实现代码:
复制代码 代码如下:
doc.bind({
'dragenter':function(e){
$("#brsbox").addClass("dragbrowse");
dropbox.addClass("shine");
return false;
},
'dragleave':function(e){
dropbox.removeClass("shine");
return false;
},
'drop':function(e){
stopdft(e);}
});
dropbox.bind({
'dragenter':function(e){
dropbox.addClass("candrop");
stopdft(e);},
'dragleave':function(e){
dropbox.removeClass("candrop");
stopdft(e);},
'dragover':function(e){
stopdft(e);},
'drop':function(e){
}
对于不支持拖拽的浏览器:
可惜的是 某些浏览器并不支持文件拖拽读取,这其中包括IE9等较现代的浏览器。所以我们必须为不支持拖拽的浏览器准备普通文件浏览上传作为备用方案。
当不支持拖拽文件读取时,界面如下:
实现检测的代码如下:
复制代码 代码如下:
it.detectDragable = function(){
filedrag = !!window.FileReader;
if(!filedrag) return;
$("#avtcnt").addClass('dragable');
文件放置时的处理:
文件放置到可接受区域时,请注意这时候无论你拖放在鼠标上的文件是单个还是多个,在浏览器和操作系统之间传送的e.dataTransefer.files总是复数。也就是多个文件。这也就意味着你需要循环处理鼠标上所携带的文件。
代码如下:
复制代码 代码如下:
dropdom.addEventListener('drop',function(e){
it.handlefile(e.dataTransfer.files);
stopdft(e);},false);
};
it.handlefile = function(files){
var noimg = 0;
for(var i=0; i<files.length; i++){
var file = files[i];
if(!file.type.match(/image*/)){
noimg ++;
if(noimg ==files.length){
QSL.optTips('请选择jpg, png, gif 等格式的图片');
return false;
}
continue;
}
var reader = new FileReader();
reader.onload = function(e){
var img = document.createElement('img');
img.src = reader.result;
setTimeout(function(){
it.imgSize = {
w:img.width,
h:img.height
};
},500);
dropdom.innerHTML="";
img.className ='localimg';
it.imgData = reader.result;
dropdom.appendChild(img);
imagedata.empty().val(reader.result);
dropbox.addClass("droped");
clearner.show();
};
reader.readAsDataURL(file);
}
处理拖拽到浏览器的文件
其中 stopdft(e) 是为了防止浏览器默认操作,不以浏览器打开文件。而转由脚本来处理拖放的文件。
这个流程中,我们需要的是图片文件,所以便利操作 e.dataTransfer.files 对象,查找类型为image的文件。
如果没有,则会提示。
读取文件的关键代码:
var reader = new FileReader();
reader.onload = function(e){
var img = document.createElement('img');
img.src = reader.result;
};
reader.readAsDataURL(file);
本例中我们需要读取图片的高度和宽度属性。所以我们做了如下操作
setTimeout(function(){
it.imgSize = {
w:img.width,
h:img.height
};
},500);
虽然是本地文件读取,但是仍然要延时来保证图片确实读取完毕。否则在某些浏览器中会取不到宽高的值。(可否有其他更简便方法?望指出)
删除现有图片,重置拖拽区域:
浏览读取完本地图片之后,要给用户提供删除和重置的选项。(如果是直接上传当然更简便)
复制代码 代码如下:
it.resetDropbox = function(){
dropbox.attr("class","dropbox")
.empty()
.text("将文件拖拽至此区域");
imgData = '';
it.imgData = '';
it.imgSize = {w:0,h:0};
picsub.removeClass("uploading")
.find("button").removeAttr("disabled")
.text("上传");
imagedata.val('');
clearner.hide();
重置拖拽区域
到这里拖放读取文件的流程基本结束。
利用拖放,读取本地文件的其他优点:
普通的上传更改图片流程是:选择图片-上传图片-上传成功-服务器返回图片-客户端浏览效果
而如果利用拖放读取本地文件则可省去服务器返回 图片的步骤,直接利用reader.result返回的数据。
这样就节省了从服务器读取图片的延迟,并且节省了往返的数据流量。所以只需确认服务器端图片上传成功,图片预览调取本地数据即可:
代码:
复制代码 代码如下:
function initImageCrop(url){
var t = document.getElementById("target"),
p = document.getElementById("preview"),
b = browseImage,
s = [],
ts = [];
if(url=='data'){
t.src = b.imgData;
p.src = b.imgData;
posImage(b.imgSize.w,b.imgSize.h);
}else{
var cutimg = new Image();
cutimg.onload = function(){
t.src = url;
p.src = url;
posImage(cutimg.width,cutimg.height);
}
cutimg.src = url;
图片上传成功后的处理
完整DEMO预览(静态文件暂时没有上传成功后的展示(:)
DEMO脚本