前端框架---webuploader组件的封装

webuploader组件的封装

在做项目的时候,之前的同事用的是原生的html写的文件上传,用的是input type=file,这种方式来写的,在兼容性上有很大的问题,在前端的时候,出现了很多的bug,但是却没法解决,之后客户还觉得我们能力不行,我直接使用webuploader这个控件,官方说是兼容ie安卓4+ios等系统,我看兼容性这么好,就直接用这个就好了,但是看他们的官网是在是受不了啊,太可怕了,API很凌乱看的好累,之后花了大约一天半的时间,基于webuploader的功能的一个插件(说是插件,其实就是将webuploader的功能集成了一下,自己用着方便)。

下面就是我自己集成的webuploader的代码

;(function (window, $) {
    'use strict';
    //全局定义webuploader对象,引入webuploader
    var WebUploader = null;

    /**
     * 建立一个对象,用于实例化的作用,添加一些属性
     */
    function webUploadFunction() {
        this.opction = null;
        this.patchOpction = null;
        this.swf_path = "";//swf的地址
        this.uploader = null;
        WebUploader = window.WebUploader;
    }

    /**
     * 初始化全局环境,以及webuploader里面的事件方法。
     * 调用直接使用WUF.init({});进行调用初始化
     * @param opction
     */
    webUploadFunction.prototype.init = function (opction) {
        //判断是不是引用了webuploader的js
        if (!WebUploader) {
            throw new Error('请引入对应的webuploader.js文件,具体下载地址在webuploader官网');
        }

        //判断是不是支持浏览器
        if (!WebUploader.Uploader.support()) {
            throw new Error('Web Uploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器');
        }
        this.opction = opction;
        this.swf_path = this.opction["swf_path"];
        this.patchOpction = this.opction["patchOpction"];

        //路径的必传选项
        if (!this.swf_path) {
            throw new Error('webuploader 组件的swf路径为空,请设置路径');
        }

        // HOOK 这个必须要再uploader实例化前面,详情见 http://fex.baidu.com/webuploader/document.html#hook
        /*
            add-file	        files: File对象或者File数组	用来向队列中添加文件。
            before-send-file	file: File对象	在文件发送之前request,此时还没有分片(如果配置了分片的话),可以用来做文件整体md5验证。
            before-send	        block: 分片对象	在分片发送之前request,可以用来做分片验证,如果此分片已经上传成功了,可返回一个rejected promise来跳过此分片上传
            after-send-file	    file: File对象	在所有分片都上传完毕后,且没有错误后request,用来做分片验证,此时如果promise被reject,当前文件上传会触发错误。
        */
        //判断是不是分片上传,要是分片上传,则要在初始化之前去做Hook,所以添加了一个判断
        if(this.patchOpction){
            WebUploader.Uploader.register({
                'add-file':'addFile',
                'before-send-file': 'beforeSendFile',
                'before-send': 'beforeSend',
                'after-send-file':'afterSendFile'
            }, {
                addFile:this.patchOpction["addFile"]||function(files){
                    console.log(files);
                },
                beforeSendFile:this.patchOpction["beforeSendFile"]||function (file) {
                    console.log(file);
                },
                beforeSend: this.patchOpction["beforeSend"]||function (block) {
                    console.log(block);
                },
                afterSendFile:this.patchOpction["afterSendFile"]||function(file){
                    console.log(file);
                }
            });
        }

        // 实例化
        this.uploader = WebUploader.create({

            // 指定Drag And Drop拖拽的容器,如果不指定,则不启动
            dnd: this.opction["dnd"],

            //是否禁掉整个页面的拖拽功能,如果不禁用,图片拖进来的时候会默认被浏览器打开。
            disableGlobalDnd: this.opction["disableGlobalDnd"] || false,

            //指定监听paste事件的容器,如果不指定,不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为document.body
            paste: document.body,

            // 指定选择文件的按钮容器,不指定则不创建按钮。
            pick: {
                //指定选择文件的按钮容器,不指定则不创建按钮。注意 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。
                id: '#' + this.opction["selectFileId"],

                //{String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。
                innerHTML: this.opction["selectFileLabel"] || '点击选择图片',

                // {Boolean} 是否开起同时选择多个文件能力
                multiple: this.opction["selectFileMultiple"] || false
            },

            //指定接受哪些类型的文件。 由于目前还有ext转mimeType表,所以这里需要分开指定。
            accept: this.opction["accept"] || {

                //文字描述
                title: 'Images',

                //允许的文件后缀,不带点,多个用逗号分割。
                extensions: 'gif,jpg,jpeg,bmp,png',

                //多个用逗号分割。
                mimeTypes: 'image/*'
            },

            //配置生成缩略图的选项。默认如下
            thumb: this.opction["thumb"]||{
                width: 110,
                height: 110,

                // 图片质量,只有type为`image/jpeg`的时候才有效。
                quality: 70,

                // 是否允许放大,如果想要生成小图的时候不失真,此选项应该设置为false.
                allowMagnify: true,

                // 是否允许裁剪。
                crop: true,

                // 为空的话则保留原有图片格式。
                // 否则强制转换成指定的类型。
                type: 'image/jpeg'
            },

            //配置压缩的图片的选项。如果此选项为false, 则图片在上传前不进行压缩。默认如下
            compress: this.opction["compress"] || {
                width: 1600,
                height: 1600,

                // 图片质量,只有type为`image/jpeg`的时候才有效。
                quality: 90,

                // 是否允许放大,如果想要生成小图的时候不失真,此选项应该设置为false.
                allowMagnify: false,

                // 是否允许裁剪。
                crop: false,

                // 是否保留头部meta信息。
                preserveHeaders: true,

                // 如果发现压缩后文件大小比原来还大,则使用原来图片
                // 此属性可能会影响图片自动纠正功能
                noCompressIfLarger: false,

                // 单位字节,如果图片大小小于此值,不会采用压缩。
                compressSize: 0
            },

            //{Boolean} [可选] [默认值:false] 设置为 true 后,不需要手动调用上传,有文件选择即开始上传。
            auto: this.opction["auto"] || false,

            //{Object} [可选] [默认值:html5,flash] 指定运行时启动顺序。默认会想尝试 html5 是否支持,如果支持则使用 html5, 否则则使用 flash.可以将此值设置成 flash,来强制使用 flash 运行时。
            runtimeOrder:this.opction["runtimeOrder"]||"html5,flash",

            // {Boolean} [可选] [默认值:false] 是否允许在文件传输时提前把下一个文件准备好。 对于一个文件的准备工作比较耗时,比如图片压缩,md5序列化。 如果能提前在当前文件传输期处理,可以节省总体耗时。
            prepareNextFile: this.opction["prepareNextFile"] || false,

            //{Boolean} [可选] [默认值:false] 是否要分片处理大文件上传。
            chunked: this.opction["chunked"] || false,

            //{Boolean} [可选] [默认值:5242880] 如果要分片,分多大一片? 默认大小为5M.
            chunkSize: this.opction["chunkSize"] || 1024 * 1024 * 5,

            //{Boolean} [可选] [默认值:2] 如果某个分片由于网络问题出错,允许自动重传多少次?
            chunkRetry: this.opction["chunkRetry"] || 2,

            //上传并发数。允许同时最大上传进程数。
            threads:this.opction["threads "]||3,

            //设置文件上传域的name。
            fileVal:this.opction["fileVal"]||"file",

            //文件上传方式,POST或者GET。
            method:this.opction["method"]||"POST",

            //文件上传请求的参数表,每次发送都会发送此对象中的参数。
            formData:this.opction["formData "]||{},

            //是否已二进制的流的方式发送文件,这样整个上传内容php://input都为文件内容, 其他参数在$_GET数组中。
            sendAsBinary:this.opction["sendAsBinary"]||false,

            //验证文件总数量, 超出则不允许加入队列。
            fileNumLimit: this.opction["fileNumLimit"] || 1,

            //验证文件总大小是否超出限制, 超出则不允许加入队列
            fileSizeLimit: this.opction["fileSizeLimit"] || 5 * 1024 * 1024,    // 200 M

            //验证单个文件大小是否超出限制, 超出则不允许加入队列。
            fileSingleSizeLimit: this.opction["fileSingleSizeLimit"] || 1 * 1024 * 1024,    // 50 M

            //{Boolean} [可选] [默认值:undefined] 去重, 根据文件名字、文件大小和最后修改时间来生成hash Key.
            duplicate:this.opction["duplicate"],

            // swf文件路径
            swf: this.swf_path,

            //服务器地址
            server: this.opction["server"],

        });

        //当文件被加入队列之前触发,此事件的handler返回值为false,则此文件不会被添加进入队列。
        this.uploader.on('beforeFileQueued',this.opction["beforeFileQueued"]||function(file){
            console.log(file);
        }),

        //当文件被加入队列以后触发。
        this.uploader.on('fileQueued', this.opction["fileQueued"] || function (file) {
            console.log('fileQueued',file);
        });

        //当一批文件添加进队列以后触发。
        this.uploader.on('filesQueued', this.opction["filesQueued"] || function (file) {

            console.log('filesQueued',file);
        });

        //当文件被移除队列后触发。
        this.uploader.on('fileDequeued', this.opction["fileDequeued"] || function (file) {

            console.log('fileDequeued',file);
        });

        //当 uploader 被重置的时候触发。
        this.uploader.on("reset", this.opction["reset"] || function () {
        });

        //当开始上传流程时触发。
        this.uploader.on("startUpload", this.opction["startUpload"] || function () {
        });

        //当开始上传流程暂停时触发。
        this.uploader.on("stopUpload", this.opction["stopUpload"] || function () {
        });

        //当所有文件上传结束时触发。
        this.uploader.on("uploadFinished", this.opction["uploadFinished"] || function () {
        });

        //某个文件开始上传前触发,一个文件只会触发一次。
        this.uploader.on("uploadStart", this.opction["uploadStart"] || function (file) {
            console.log("uploadStart",file);
        });

        /*当某个文件的分块在发送前触发,主要用来询问是否要添加附带参数,大文件在开起分片上传的前提下此事件可能会触发多次。
            object {Object}
            data {Object}默认的上传参数,可以扩展此对象来控制上传参数。
            headers {Object}可以扩展此对象来控制上传头部。
        */
        this.uploader.on('uploadBeforeSend', this.opction["uploadBeforeSend"] || function (obj, data, headers) {
            console.log('uploadBeforeSend',obj, data, headers);
        });

        /*
            当某个文件上传到服务端响应后,会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为false, 则此文件将派送server类型的uploadError事件
            object {Object}
            ret {Object}服务端的返回数据,json格式,如果服务端不是json格式,从ret._raw中取数据,自行解析
        */
        this.uploader.on('uploadAccept', this.opction["uploadAccept"] || function (obj, ret) {
            console.log('uploadAccept',obj,ret);
        });

        /* 上传过程中触发,携带上传进度。
            file {File}File对象
            percentage {Number}上传进度
        */
        this.uploader.on('uploadProgress', this.opction["uploadProgress"] || function (file, percentage) {
            console.log('uploadProgress',file, percentage);
        });

        /* 当文件上传出错时触发。
            file {File}File对象
            reason {String}出错的code
        */
        this.uploader.on('uploadError', this.opction["uploadError"] || function (file,reason) {
            console.log('uploadError',file, reason ,"上传失败");
        });

        /*
            文件上传成功,给item添加成功class, 用样式标记上传成功。
            file {File}File对象
            response {Object}服务端返回的数据
        */
        this.uploader.on('uploadSuccess', this.opction["uploadSuccess"] || function (file,response) {
            console.log('uploadSuccess',file,response, "上传成功");
        });

        // 不管成功或者失败,文件上传完成时触发。
        this.uploader.on('uploadComplete', this.opction["uploadComplete"] || function (file) {
            console.log('uploadComplete',file, "上传结束")
        });

        /*
            当validate不通过时,会以派送错误事件的形式通知调用者。通过upload.on('error', handler)可以捕获到此类错误,目前有以下错误会在特定的情况下派送错来。
            Q_EXCEED_NUM_LIMIT 在设置了fileNumLimit且尝试给uploader添加的文件数量超出这个值时派送。
            Q_EXCEED_SIZE_LIMIT 在设置了Q_EXCEED_SIZE_LIMIT且尝试给uploader添加的文件总大小超出这个值时派送。
            Q_TYPE_DENIED 当文件类型不满足时触发。

            type {String}错误类型。
         */
        this.uploader.on("error", this.opction["error"] || function (type) {
            console.log("error",type);
        });
        return this.uploader;
    };

    /**
     * 在window里面进行实例化处理
     * @type {webUploadFunction}
     */
    window.WUF = new webUploadFunction();
})(window, $);

下面是html里面的调用方法 :主要是bootatrap的css和js,引用了jquery,webuploader的css和js

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传demo</title>
    <!-- 引入css -->
    <link rel="stylesheet" href="../plugin/bootstrap/css/bootstrap.css">
    <link rel="stylesheet" href="../plugin/webupload/css/webuploader.css">
    <style>
        .all{
            height: 500px;
        }

    </style>


</head>
<body>

<div class="container-fluid all">
    <div class="row all">
        <div class="col-md-3 all">
            <h4>上传单张图片</h4>
            <div class="wu-example">
                <div class="btns">
                    <div id="pickerOne">选择大文件</div>
                    <button id="ctlBtnOne" class="btn btn-default" onclick="uploaderOne()">开始上传</button>
                </div>
            </div>
        </div>
        <div class="col-md-3 all">
            <h4>分片上传单张图片</h4>
            <div class="wu-example">
                <div class="btns">
                    <div id="pickerTwo">选择大文件</div>
                    <button id="ctlBtnTwo" class="btn btn-default" onclick="uploaderTwo()">开始上传</button>
                </div>
            </div>
        </div>
        <div class="col-md-3 all">
            <h4>上传多张图片</h4>
            <div class="wu-example">
                <div class="btns">
                    <div id="pickerThree">选择大文件</div>
                    <button id="ctlBtnThree" class="btn btn-default" onclick="uploaderThree()">开始上传</button>
                </div>
            </div>
        </div>
        <div class="col-md-3 all">
            <h4>分片上传多张图片</h4>
            <div class="wu-example">
            <div class="btns">
                <div id="pickerFour">选择大文件</div>
                <button id="ctlBtnFour" class="btn btn-default" onclick="uploaderFour()">开始上传</button>
            </div>
        </div>
        </div>
    </div>
</div>

<!-- 引入js控件 -->
<script src="../plugin/jQuery/jquery-1.2.4.js"></script>
<script src="../plugin/bootstrap/js/bootstrap.js"></script>
<script src="../plugin/webupload/js/webuploader.js"></script>
<script src="../plugin/webupload/js/webuploader.nolog.js"></script>
<script src="../js/webuploadFunction.js"></script>
<!-- 引入业务js -->
<script src="../js/demo.js"></script>
</body>
</html>

下面是业务的js :分了四个模块,感觉已经把文件上传都已经概括了。

/**  公共变量的定义  **/
var httpRequestUrl = "http://localhost:8080";
var uploaderObjOne = null;
var uploaderObjTwo = null;
var uploaderObjThree = null;
var uploaderObjFour = null;

/**  初始化的方法的定义和执行 **/
demoInit();

function demoInit(){

    //初始化文件上传控件
    uploaderObjOne = WUF.init({
        selectFileId:'pickerOne',
        swf_path:'../plugin/webupload/swf/Uploader.swf',
        server:httpRequestUrl+'/break/fileUpload',
        fileNumLimit:1,
        fileSizeLimit:1024*1024*5,
        fileSingleSizeLimit:1024*1024*5,
        error:function(type){

        }
    });

    //初始化文件上传控件
    uploaderObjTwo = WUF.init({
        selectFileId:'pickerTwo',
        swf_path:'../plugin/webupload/swf/Uploader.swf',
        server:httpRequestUrl+'/break/fileUpload',
        fileNumLimit:1,
        fileSizeLimit:1024*1024*50,
        fileSingleSizeLimit:1024*1024*50,
        patchOpction:{
            beforeSendFile:function(file){
                // Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
                var task = new $.Deferred();
                // 根据文件内容来查询MD5
                uploaderObjTwo.md5File(file).progress(function (percentage) {   // 及时显示进度
                    console.log('计算md5进度:', percentage);
                }).then(function (val) { // 完成
                    console.log('md5 result:', val);
                    file.md5 = val;
                    // 模拟用户id
                    // file.uid = new Date().getTime() + "_" + Math.random() * 100;
                    file.uid = WebUploader.Base.guid();
                    // 进行md5判断
                    $.post(httpRequestUrl+"/break/checkFileMd5", {uid: file.uid, md5: file.md5, "Authorization": localStorage.token},
                        function (data) {
                            console.log(data.status);
                            var status = data.status.value;
                            task.resolve();
                            if (status == 101) {
                                // 文件不存在,那就正常流程
                            } else if (status == 100) {
                                // 忽略上传过程,直接标识上传成功;
                                uploaderObjTwo.skipFile(file);
                                file.pass = true;
                            } else if (status == 102) {
                                // 部分已经上传到服务器了,但是差几个模块。
                                file.missChunks = data.data;
                            }
                        });
                });
                return $.when(task);
            },
            beforeSend:function(block){
                console.log("block")
                var task = new $.Deferred();
                var file = block.file;
                var missChunks = file.missChunks;
                var blockChunk = block.chunk;
                console.log("当前分块:" + blockChunk);
                console.log("missChunks:" + missChunks);
                if (missChunks !== null && missChunks !== undefined && missChunks !== '') {
                    var flag = true;
                    for (var i = 0; i < missChunks.length; i++) {
                        if (blockChunk == missChunks[i]) {
                            console.log(file.name + ":" + blockChunk + ":还没上传,现在上传去吧。");
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        task.reject();
                    } else {
                        task.resolve();
                    }
                } else {
                    task.resolve();
                }
                return $.when(task);
            }
        }
    });

    //初始化文件上传控件
    uploaderObjThree = WUF.init({
        selectFileId:'pickerThree',
        selectFileMultiple:true,
        swf_path:'../plugin/webupload/swf/Uploader.swf',
        server:httpRequestUrl+'/break/fileUpload',
        fileNumLimit:5,
        fileSizeLimit:1024*1024*25,
        fileSingleSizeLimit:1024*1024*5,
    });

    //初始化文件上传控件
    uploaderObjFour = WUF.init({
        selectFileId:'pickerFour',
        selectFileMultiple:true,
        swf_path:'../plugin/webupload/swf/Uploader.swf',
        server:httpRequestUrl+'/break/fileUpload',
        fileNumLimit:5,
        chunked: true,
        fileSizeLimit:1024*1024*100,
        fileSingleSizeLimit:1024*1024*100,
        patchOpction:{
            beforeSendFile:function(file){
                // Deferred对象在钩子回掉函数中经常要用到,用来处理需要等待的异步操作。
                var task = new $.Deferred();
                // 根据文件内容来查询MD5
                uploaderObjTwo.md5File(file).progress(function (percentage) {   // 及时显示进度
                    console.log('计算md5进度:', percentage);
                }).then(function (val) { // 完成
                    console.log('md5 result:', val);
                    file.md5 = val;
                    // 模拟用户id
                    // file.uid = new Date().getTime() + "_" + Math.random() * 100;
                    file.uid = WebUploader.Base.guid();
                    // 进行md5判断
                    $.post(httpRequestUrl+"/break/checkFileMd5", {uid: file.uid, md5: file.md5, "Authorization": localStorage.token},
                        function (data) {
                            console.log(data.status);
                            var status = data.status.value;
                            task.resolve();
                            if (status == 101) {
                                // 文件不存在,那就正常流程
                            } else if (status == 100) {
                                // 忽略上传过程,直接标识上传成功;
                                uploaderObjTwo.skipFile(file);
                                file.pass = true;
                            } else if (status == 102) {
                                // 部分已经上传到服务器了,但是差几个模块。
                                file.missChunks = data.data;
                            }
                        });
                });
                return $.when(task);
            },
            beforeSend:function(block){
                console.log("block")
                var task = new $.Deferred();
                var file = block.file;
                var missChunks = file.missChunks;
                var blockChunk = block.chunk;
                console.log("当前分块:" + blockChunk);
                console.log("missChunks:" + missChunks);
                if (missChunks !== null && missChunks !== undefined && missChunks !== '') {
                    var flag = true;
                    for (var i = 0; i < missChunks.length; i++) {
                        if (blockChunk == missChunks[i]) {
                            console.log(file.name + ":" + blockChunk + ":还没上传,现在上传去吧。");
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        task.reject();
                    } else {
                        task.resolve();
                    }
                } else {
                    task.resolve();
                }
                return $.when(task);
            }
        }
    });

}

/**  方法的定义 **/

//开始上传 上传单张图片
function uploaderOne(){
    uploaderObjOne.upload();

}

//开始上传 分片上传单张图片
function uploaderTwo(){
    uploaderObjTwo.upload();
}

//开始上传 上传多张图片
function uploaderThree(){
    uploaderObjThree.upload();
}

//开始上传 分片上传多张图片
function uploaderFour(){
    uploaderObjFour.upload();
}

之后就是webuploader里面的文件去哪下载了,在官网就可以进行下载了,下载之后dist这个文件夹就可以了,这里用npm脚手架生成的,所以放在了这个文件夹,所需要的文件就在这了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值