基于NodeJs的Express及Webuploader实现大文件分片上传与合并(二)——组件化实现

来源:互联网 发布:运行 Windows 编辑:程序博客网 时间:2024/05/17 04:24

基于第一篇的实现大文件分片上传与合并的实现,想进一步结合一下模块化,因此就有了本篇内容:大文件分片上传于合并的组件化实现

目前浏览器端比较流行的就是Requirejs,因此本篇结合Requirejs,进一步将功能组件化。

其实利用Requirejs改造之前的功能是比较容易的,按照Requirejs官方的文档有以下几步:

1)下载Requirejs。

2)在view模板文件中改造之前的js引用方式。

3)将原先的逻辑功能抽象成一个组件,并在页面调用的Requirejs统一入口文件中调用即可。

下面就详细介绍一下2、3步,所有的代码见我的GitHub开发分支。

第2步很简单,贴一下代码之前upload.jade改造后的代码,其中html dom部分不变,只是把多个script改成requirejs引入的方式:

extends ../layout/frontblock content    link(rel="stylesheet" type="text/css" href="plugins/webuploader/webuploader.css")    link(rel="stylesheet" type="text/css" href="css/front/upload.css")    #uploader.wu-example        .dndArea            .file-select                #picker 选择文件                p 或将文件拖到这里        // 用来存放文件信息        #thelist.uploader-list        button#ctlBtn.btn.btn-default 开始上传    script(src="js/require-2.1.11.min.js" defer async="true" data-main="js/front/upload.js")
第3步比较重要,也是关键。首先抽象逻辑功能为一个组件,这势必要预先定义一下requirejs的config,我写到了js/front/upload.js里面,同时调整了组件的目录结构,贴一下配置:

requirejs.config({    baseUrl: 'js',    paths: {        jquery: 'jquery-1.8.3.min',        webuploader: '../plugins/webuploader/webuploader',        md5: 'md5.min',    }});
其次就是要抽象改造功能为Requirejs的组件,改造的思路我借鉴了js的prototype原型模式,具体的原型模式可以参见我的另一篇文章:JavaScript面向对象编程之封装(一)。

采用原型模式的基本框架(套路)如下:

function ClassName(a, b){        this.xxx = a;        this.yyy = b;}ClassName.prototype.zzz = function() {        console.log('zzz');};var obj = new ClassName('x', 'y');
根据原型模式封装上传组件:
define(['jquery', 'md5', 'webuploader'], function ($, md5, WebUploader) {    /**     * 类     * @constructor     */    function Uploader() {        //-------------公有属性-------------        this.config = {};        this.uploader = {};    }    // -------------公共方法--------------    // 组件初始化(公有方法)    Uploader.prototype.init = function (cfg) {        if (!this.support()) {            return false;        }        //-------------私有属性-------------        var _config = {            // 选完文件后,是否自动上传。            auto: false,            // swf文件路径            swf: '../../webuploader/Uploader.swf',            // 文件接收服务端。            server: '/upload_chunks',            // 选择文件的按钮。可选。            // 内部根据当前运行是创建,可能是input元素,也可能是flash.            pick: {                id: '#picker',                label: '点击选择文件'            },            // 配置压缩的图片的选项            compress: false,            // 拖拽配置            dnd: '.dndArea',            disableGlobalDnd: false,            // 此功能为通过粘贴来添加截屏的图片。建议设置为document.body            paste: document.body,            // 分片上传配置            chunked: true,// 开起分片上传。            chunkSize: Math.pow(1024, 2),// 单位字节(Byte)            threads: 1,//上传并发数            // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!            resize: false        };        //-----------------私有方法-----------------        // 初始化配置和对象        function _initConfig(cfg) {            this.config = $.extend(_config, cfg);            this.uploader = WebUploader.create(this.config);        }        // 初始化对象事件        function _initEvent() {            var that = this;            // 当有文件被添加进队列的时候            this.uploader.on('fileQueued', function (file) {                var $list = $(".uploader-list");                var item = '<div id="' + file.id + '" class="item">' +                    '<div class="file-info">' +                    '<h4 class="info">' + file.name + '</h4>' +                    '<p class="state">等待上传...</p>' +                    '</div>' +                    '</div>';                $list.append(item);            });            // 某个文件开始上传前触发,一个文件只触发一次            this.uploader.on('uploadStart', function (file) {                that.uploader.options.formData.guid = md5([file.id, file.name, file.size, file.type, file['__hash']].join(''));            });            // 文件上传过程中创建进度条实时显示。            this.uploader.on('uploadProgress', function (file, percentage) {                var $li = $('#' + file.id),                    $percent = $li.find('.progress .progress-bar');                // 避免重复创建                if (!$percent.length) {                    var progress = '<div class="progress progress-striped active">' +                        '<div class="progress progress-bar" role="progressbar" style="width: 0%">' +                        '</div>' +                        '</div>';                    $percent = $(progress).prependTo($li).find('.progress-bar');                }                $li.find('p.state').text('上传中');                $percent.css('width', percentage * 100 + '%');            });            this.uploader.on('uploadSuccess', function (file) {                // console.log(file);                // 如果是分片上传,文件上传成功后执行分片合并并返回Get文件的url                if (that.uploader.options.chunked) {                    $.post('/merge_chunks', {                        'hash': md5([file.id, file.name, file.size, file.type, file['__hash']].join('')),                        'name': file.name,                        'size': file.size                    }, function (data) {                        if (data.status) {                            $('#' + file.id).find('p.state').text('已上传');                            $('#' + file.id).find('.progress-bar').css({                                'background-image': 'url(' + data.url + ')',                                'background-size': 'cover',                                'background-repeat': 'no-repeat'                            });                        } else {                            $('#' + file.id).find('p.state').text('上传错误!');                        }                    }, 'json');                }            });            this.uploader.on('uploadError', function (file) {                $('#' + file.id).find('p.state').text('上传出错');            });            this.uploader.on('uploadComplete', function (file) {                // $('#' + file.id).find('.progress').fadeOut();            });        }        _initConfig.apply(this, [cfg]);        _initEvent.apply(this);    };    // 组件支持    Uploader.prototype.support = function () {        try {            if (!WebUploader.Uploader.support()) {                alert('Web Uploader 不支持您的浏览器!如果你使用的是IE浏览器,请尝试升级 flash 播放器');                throw new Error('WebUploader does not support the browser you are using.');            }            return true;        } catch (e) {            if (e instanceof Error) {                console.error(e.message);            } else {                console.error('Error!');            }            return false;        }    };    // 开始下载    Uploader.prototype.startUpload = function () {        if (!this.support()) {            return false;        }        this.uploader.upload();    };    return new Uploader();});
这里,用到了私有属性和方法进行初始化,将Webuploader实例作为封装类的公共属性。

接下来让我们试着调用该组件,我写在upload.js里:

requirejs(['modules/uploader'], function (Uploader) {    Uploader.init({        pick: {            id: '#picker',            label: '选择文件'        },        threads: 2,    });    $('#ctlBtn').on('click', function (event) {        event.stopPropagation();        Uploader.startUpload();    });});
其中Uploader.init方法也可以不传。
至此,整体的功能模块化改造完毕,还是相对比较简单的,关键点在于模块化组件的实现。
另外,也许你有更好的封装模块化组件方式,我的仅供参考交流,不对之处还望大神们多多指正。

0 0
原创粉丝点击