zoukankan      html  css  js  c++  java
  • 打造 html5 文件上传组件,实现进度显示及拖拽上传,支持秒传+分片上传+断点续传,兼容IE6+及其它标准浏览器

    老早就注册了博客园帐号,昨天才发现,连博客都没开,Github也是一样,深觉惭愧,赶紧潜个水压压惊`(*∩_∩*)′

    言归正传。大概许多人都会用到文件上传的功能,上传的库貌似也不少,比如(jQuery File UploaderFineUploaderUploadifyBaidu Web Uploader 等等),功能都很强大,代码量一般也较大。当时心想,就这么个小功能,杀鸡焉用牛刀,用库的话还得熟悉它的用法,有的需要引入额外的库,纯Flash的不考虑,还是动手造个轮子得了,至少造过之后能知道底层的原理,关键是,自己写的东西,维护和修改方便,对过程可以进行全方位的控制。造个轮子简单,造个好用的轮子却就不是那么简单了。上传功能很快完成,但下次又用到的时候,却发现拿过来用需要修改不少东西,一是使用的JS库发生了变化,再就是UI界面完全不同,当时将上传逻辑和界面写的死死的,遇到不同的情况就需要针对性的改造。针对单一情况写的东西当然最轻量,只用考虑当前情况,不用的功能可以统统抛开,能做到最精简,但不方便重用。一个轮子如果不能重用,那当然不能算一个合格的轮子。意识到这点,而且既然已经走上了造轮子这条路,需要的核心功能也没有大的变化,那还是走下去吧。然后一路修修改改,最后完成了一个可用的版本。

    v1.4版本已支持秒传+分片上传+断点续传(IE10+、其它标准浏览器),具体请参考Github代码

    关于我的上传控件

    特点:

    • 轻量级,不依赖任何JS库,核心代码(Q.Uploader.js)仅约700行,min版本加起来不到12KB
    • 纯JS代码,无需Flash,无需更改后台代码即可实现带进度条(IE10+、其它标准浏览器)的上传,其它(eg:IE6+)自动降级为传统方式上传
    • 上传核心与UI界面分离,可以很方便的定制上传界面包括上传按钮
    • 上传文件的同时可以指定上传参数,支持上传类型过滤
    • 完善的事件回调,可针对上传的每个过程进行单独处理
    • 方便的UI接口,上传界面可以随心所欲的定制

    简单调用示例(暴露的全局对象为Q):

    var uploader = new Q.Uploader({
        url: "api/upload.ashx?type=file",
        target: document.getElementById("upload-target"),
        view: document.getElementById("upload-view"),
    
        //html5: true,       //是否启用html5上传,默认为true
        //multiple: true,    //是否允许多选(仅html5模式有效),默认为true
        //auto: true,        //添加任务后是否立即上传,默认为true
        
        //允许或不允许上传的文件类型 (allows 与 disallows 可单一或组合使用)
        //allows: ".txt,.jpg,.png,.gif,.zip,.rar,.7z",
        //disallows:".exe"
    
        //每次上传都会发送的参数(POST方式)
        data: { user: "Devin" }
    });

    详细见示例代码或 Github(感觉逼格瞬间提升了有木有,*^_^* ),示例代码和源码在文章末尾

    https://github.com/devin87/web-uploader

    原理

    1. html5上传

    这个需要浏览器支持,无论是html5上传还是和html4上传,html上传控件都是必不可少的,即:

    <input type="file">
    //监听 input 的 change 事件,获取要上传的数据
    input.onchange = function () {
        //input.files 属性需要浏览器支持
        var files = this.files;
    
        for (var i = 0, len = files.length; i < len; i++) {
            var file = files[i];
    
            //file.name || file.fileName  => 文件名称
            //file.size || file.fileSize  => 文件大小
    
            upload_html5(file);
        }
    };
    //html5 上传
    var xhr = new XMLHttpRequest();
    
    //上传进度事件
    xhr.upload.addEventListener("progress", function (e) { }, false);
    //上传完成(成功)事件
    xhr.addEventListener("load", function (e) {
        //获取服务器响应
        var text = e.target.responseText;
    }, false);
    //上传失败事件
    xhr.addEventListener("error", function (e) { }, false);
    //上传中断(取消)事件
    xhr.addEventListener("abort", function (e) { }, false);
    
    var fd = new FormData;
    //添加要上传的文件对象
    fd.append("file", file);
    
    xhr.open("POST", "api/upload.ashx");
    xhr.send(fd);

    2. html4上传(传统上传)

    通过将 form 的 target 指向 iframe 的 name 来实现无刷新上传

    <iframe name="html4-upload-target"></iframe>
    <form action="api/upload.ashx" method="post" enctype="multipart/form-data" target="html4-upload-target">
        <input type="file" name="upfile" />
    </form>
    //iframe load 事件
    //注意:低版本 ie 支持 iframe 的 onload 事件,不过是隐形的(iframe.onload 方式绑定的将不会触发),需要通过 attachEvent 来注册
    function bind_iframe_load(iframe, fn) {
        if (iframe.attachEvent) iframe.attachEvent("onload", fn);
        else iframe.addEventListener("load", fn, false);
    }
    
    //html4上传完成回调
    bind_iframe_load(iframe, function () {
        //获取服务器响应
        var text = iframe.contentWindow.document.body.innerHTML;
    });

    美化

    上传按钮很丑,我想美化咋整?IE10+及标准浏览器支持 input.click() 触发文件选择,有人说,低版本IE也能弹出这个框框呀,这里有个坑,弹是能弹,但是可能基于安全考虑无法获取文件数据,报拒绝访问。

    既然必须点击上传控件来选取文件,那么可以通过绝对定位让上传控件遮盖上传按钮,然后将上传控件透明度设为0,以达到隐身的效果,如此一来表面点击的是上传按钮,实际点击的是上传控件,问题也就随之解决。

    <!-- 上传按钮,样式随自己控制,假设宽高为分别为120px,36px,相对于body的边距分别为100px,100px -->
    <a class="upload-target">选择文件上传</a>
    
    <!-- 上传控件,选择文件后(change事件)将 input 追加到 form 即可 -->
    <div style="120px;height:36px;position:absolute;left:100px;top:100px;overflow:hidden;filter: alpha(opacity=0);opacity:0;">
        <input type="file" name="upfile" style="120px;height:36px;font-size:100px;" />
    </div>

    关于html4上传,刚好看到一篇 利用iframe无刷新上传文件的坑 文章,有兴趣的童鞋可以看看。

    拖拽文件上传

    文件拖拽利用了 HTML5 中的 Drag and Drop 特性,可以直接将本地电脑上的文件拖拽到网页中。

    1. 定义拖拽区域

    <div id="drop-area">将文件拖拽到此区域</div>

    2. 获取拖拽数据并上传

    var boxDropArea = $("#drop-area")[0];
    
    //TODO:检测支持情况
    
    //阻止浏览器默认拖放行为
    $(boxDropArea).on("dragleave dragenter drop dragover", function (e) {
        e.preventDefault();
        e.stopPropagation();
    });
    
    //获取拖拽的文件对象并上传
    $(boxDropArea).on("drop", function (e) {
        var files = e.dataTransfer.files;
        if (!files || files.length == 0) return;
    
        for (var file in files) {
            //TODO:上传文件
            upload(file);
        }
    });

    想了解更多拖拽的信息,可以参考这篇文章 HTML5 drag & drop 拖拽与拖放简介

    代码下载

    asp.net 或其它后台示例代码

    Node.js 示例代码

    写在最后

    如果本文或本项目对您有帮助的话,请不吝点个赞。欢迎交流!

  • 相关阅读:
    瀑布流
    进度条
    图片延迟加载、scroll
    scroll 滚动广告
    json
    样式更改
    js 不同浏览器的宽度获取
    孤立点挖掘算法
    数据结构算法代码
    深入浅出JMS(一)--JMS基本概念
  • 原文地址:https://www.cnblogs.com/devin87/p/web-uploader.html
Copyright © 2011-2022 走看看