html5之多文件拖拽上传预览

来源:互联网 发布:进出口业务流程知乎 编辑:程序博客网 时间:2024/04/29 22:57

最近对于html5预览功能很是感兴趣,特地拿出来研究一小下,并以一个小项目举例讲解。

 h5中的input有个type=file 就是文件上传控件,有个属性multiple就是h5新增的支持多选上传文件。用法很简单:

<input type="file"  multiple />

下面着重探讨一下拖拽上传并预览。

---------------------------------------------------------------------------------------------------------------------------------------------

首先定义我们整个过程中所需要用到的变量以及方法。

var zip_dragFile = {    fileInput: null,//html file控件    dragDrop: null,//拖拽敏感区域    upButton: null,//提交按钮    url: "",//ajax地址    fileFilter: [],//过滤后的文件数组    filter: function(files) {//选择文件组的过滤方法    return files;    },    onSelect: function() {},//文件选择后    onDelete: function() {},//文件删除后    onDragOver: function() {},//文件拖拽到敏感区域时    onDragLeave: function() {},//文件离开到敏感区域时    onProgress: function() {},//文件上传进度    onSuccess: function() {},//文件上传成功时    onFailure: function() {},//文件上传失败时,    onComplete: function() {},//文件全部上传完毕时}

之后定义拖拽方法。h5中新增的拖拽方法说明:dragDrop为拖拽到网页后松开鼠标位置,我们新建一个数组fileFilter存放已经拖拽到页面的图片。

  1. DataTransfer 对象:退拽对象用来传递的媒介,使用一般为Event.dataTransfer。

  2. draggable 属性:就是标签元素要设置draggable=true,否则不会有效果,例如:

    <div title="拖拽我" draggable="true">xxx</div>
  3. ondragstart 事件:当拖拽元素开始被拖拽的时候触发的事件,此事件作用在被拖曳元素上

  4. ondragenter 事件:当拖曳元素进入目标元素的时候触发的事件,此事件作用在目标元素上

  5. ondragover 事件:拖拽元素在目标元素上移动的时候触发的事件,此事件作用在目标元素上

  6. ondrop 事件:被拖拽的元素在目标元素上同时鼠标放开触发的事件,此事件作用在目标元素上

  7. ondragend 事件:当拖拽完成后触发的事件,此事件作用在被拖曳元素上

  8. Event.preventDefault() 方法:阻止默认的些事件方法等执行。在ondragover中一定要执行preventDefault(),否则ondrop事件不会被触发。另外,如果是从其他应用软件或是文件中拖东西进来,尤其是图片的时候,默认的动作是显示这个图片或是相关信息,并不是真的执行drop。此时需要用用document的ondragover事件把它直接干掉。

  9. Event.effectAllowed 属性:就是拖拽的效果。

在我们项目中添加监听事件如下:

init: function() {    var self = this;    if (this.dragDrop) {        this.dragDrop.addEventListener("dragover", function(e) { self.funDragHover(e); }, false);        this.dragDrop.addEventListener("dragleave", function(e) { self.funDragHover(e); }, false);        this.dragDrop.addEventListener("drop", function(e) { self.funGetFiles(e); }, false);    }    //文件选择控件选择    if (this.fileInput) {    this.fileInput.addEventListener("change", function(e) { self.funGetFiles(e); }, false);    }    //上传按钮提交    if (this.upButton) {    this.upButton.addEventListener("click", function(e) { self.funUploadFile(e); }, false);    } }//文件拖放funDragHover: function(e) {    e.stopPropagation();    e.preventDefault();    this[e.type === "dragover"? "onDragOver": "onDragLeave"].call(e.target);    return this;}, //获取选择文件,file控件或拖放funGetFiles: function(e) {    // 取消鼠标经过样式    this.funDragHover(e);    // 获取文件列表对象    var files = e.target.files || e.dataTransfer.files;    //继续添加文件    this.fileFilter = this.fileFilter.concat(this.filter(files));    this.funDealFiles();    return this;},

拖拽时候要检测拖拽图片大小以及格式是否符合规定:

filter: function(files) {    var arrFiles = [];    for (var i = 0, file; file = files[i]; i++) {        if (file.type.indexOf("image") == 0 || (!file.type && /\.(?:jpg|png|gif)$/.test(file.name) /* for IE10 */)){            if (file.size >= 512000) {            alert('您这张"'+ file.name +'"图片大小过大,应小于500k');            } else {            arrFiles.push(file);            }        } else {             alert('文件"' + file.name + '"不是图片。');        }    }    return arrFiles;},//选中文件的处理与回调funDealFiles: function() {    for (var i = 0, file; file = this.fileFilter[i]; i++) {        //增加唯一索引值        file.index = i;    }    //执行选择回调    this.onSelect(this.fileFilter);    return this;},



其中onSelect方法才是预览的重点,其中FileReader 专门用于读取文件,根据 W3C 的定义,FileReader 接口 "提供一些读取文件的方法与一个包含读取结果的事件模型"。使用该方法使得图片在不经过后台的情况下将效果预览于浏览器。值得注意的是现在只有只有 Firefox 3.6+ 和 Chrome 6.0+ 实现了 FileReader 接口。在这之前的 web 应用程序中,实现这个效果的通常做法是将用户选择的图像文件传送至后端,后端对其进行存储,再将 URL 返回到前端,前端通过这个 URL 来显示图像。 FileReader 的突破在于使得 JavaScript 拥有了处理文件的能力,它可以异步地读取存储在用户电脑中的文件,这里所指的文件,对于 JavaScript 来说是一个 File 对象,FileReader 读取文件的全部方法皆依赖于此。浏览器检测该方法:
if ( typeof FileReader === 'undefined' ) {                alert( " 您的浏览器未实现 FileReader 接口 " );} else {                var reader = new FileReader();                // do sth.}

FileReader 的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result属性中。

方法名                        参数                                             描述

abort                         none                                            中断读取

readAsBinaryString           file                                           将文件读取为二进制码

readAsDataURL                file                                           将文件读取为DataURL

readAsText               file,[encoding]                          将文件读取为文本

readAsText: 该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。
readAsBinaryString: 这个方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。
readAsDataURL: 这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符串的实质就是 Data URI,Data URI是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。点击这里了解更多关于 Data URI 的知识。

3. 事件

FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。

事件            描述

onabort        中断时触发

onerror        出错时触发

onload         文件读取成功完成时触发

onloadend      读取完成触发,无论成功或失败

onloadstart    读取开始时触发

onprogress     读取中

文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。

reader.onload = function () {

     this.result     // 读取结果

}

代码如下:

onSelect: function(files) {    var html = '', i = 0;    $("#preview").html('<div class="upload_loading"></div>');    var funAppendImage = function() {        file = files[i];        if (file) {            var reader = new FileReader()            reader.onload = function(e) {                html = html + '<div id="uploadList_'+ i +'" class="upload_append_list"><p><strong>' + file.name + '</strong>'+                    '<a href="javascript:" class="upload_delete" title="删除" data-index="'+ i +'">                      删除</a><br />' + '<img id="uploadImage_' + i + '" src="' + e.target.result + '"class="upload_image" /></p>'+                      '<span id="uploadProgress_' + i + '" class="upload_progress"></span>' +                    '</div>';                    i++;                funAppendImage();            }            reader.readAsDataURL(file);        } else {            $("#preview").html(html);            if (html) {                //删除方法                $(".upload_delete").click(function() {                    zip_dragFile.funDeleteFile(files[parseInt($(this).attr("data-index"))]);                    return false;                });                //提交按钮显示                $("#fileSubmit").show();            } else {                //提交按钮隐藏                $("#fileSubmit").hide();            }        }    };    funAppendImage();},

至此为止,图片预览效果已经可以实现了,接下来我们要进行预览图片的删除:

//删除对应的文件funDeleteFile: function(fileDelete) {    var arrFile = [];    for (var i = 0, file; file = this.fileFilter[i]; i++) {        if (file != fileDelete) {        arrFile.push(file);        } else {        this.onDelete(fileDelete);        }    }    this.fileFilter = arrFile;    return this;},onDelete: function(file) {    $("#uploadList_" + file.index).fadeOut();},


接下来我们要自定义一些拖拽上传事件回调(都是样式以及web显示)

onDragOver: function() {    $(this).addClass("upload_drag_hover");},onDragLeave: function() {    $(this).removeClass("upload_drag_hover");},

至此为止,web端操作已经基本完成,接下来我们就要进行最后一步了--上传:

h5中有个progress方法专门检测上传文件进度:

//文件上传funUploadFile: function() {    var self = this;    for (var i = 0, file; file = this.fileFilter[i]; i++) {    (function(file) {     var xhr = new XMLHttpRequest();            if (xhr.upload) {            // 上传中(h5的upload对象监听传输事件)            xhr.upload.addEventListener("progress", function(e) {            self.onProgress(file, e.loaded, e.total);            }, false);            // 文件上传成功或是失败            xhr.onreadystatechange = function(e) {                    if (xhr.readyState == 4) {                    if (xhr.status == 200) {                        self.onSuccess(file, xhr.responseText);                            self.funDeleteFile(file);                        if (!self.fileFilter.length) {                            //全部完毕                            self.onComplete();                            }                } else {                    self.onFailure(file, xhr.responseText);                }                     }        };                    // 开始上传            xhr.open("POST", self.url, true);            xhr.setRequestHeader("X_FILENAME", file.name);            xhr.send(file);          }       })(file);    }},

在这里利用传统的xmlHttpRequest方法,无论成功失败都进行处理,随后进行结果处理:

onProgress: function(file, loaded, total) {    var eleProgress = $("#uploadProgress_" + file.index),        percent = (loaded / total * 100).toFixed(2) + '%';    eleProgress.show().html(percent);},onSuccess: function(file, response) {    $("#uploadInf").append("<p>上传成功,图片地址是:" + response + "</p>");},onFailure: function(file) {    $("#uploadInf").append("<p>图片" + file.name + "上传失败!</p>");    $("#uploadImage_" + file.index).css("opacity", 0.2);},onComplete: function() {    //提交按钮隐藏    $("#fileSubmit").hide();    //file控件value置空    $("#fileImage").val("");    $("#uploadInf").append("<p>当前图片全部上传完毕,可继续添加上传。</p>");}

ok,这个小demo到这里就完成了。调用方法:

zip_dragFile = $.extend(zip_dragFile, params);

zip_dragFile.init();

欢迎大家指教。
原创粉丝点击