jQuery File Upload 单页面多实例的实现

Posted Meadows of Heaven

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jQuery File Upload 单页面多实例的实现相关的知识,希望对你有一定的参考价值。

jQuery File Upload 的 GitHub 地址:https://github.com/blueimp/jQuery-File-Upload

插件描述:jQuery File Upload 是一个 jQuery 图片上传组件,支持多文件上传、取消、删除,上传前缩略图预览、列表显示图片大小,支持上传进度条显示。插件基于开放的标准,如 html5 和 javascript ,不需要额外的浏览器插件(例如使用Adobe 的 Flash ),在旧版浏览器中使用 XMLHttpRequest 上传文件。(参见:http://www.jq22.com/jquery-info230)。

需求:在一个页面中包含多个插件实例。例如在生鲜电商网站后台的食谱添加/编辑页面,需要上传/编辑一道菜的食材和配料,就需要在页面中同时包含两个上传实例。插件的文档中有关于单页面多实例的介绍:Multiple File Upload Widgets on the same page,里面说明很简单,把 demo 中 index.html 的 form 表单的 id 改成 class,再简单修改 js/main.js 就可以了。

在很天真的试过之后,发现根本不是这么回事,index.html 中文件域的 name 是写死的,根本无法满足单页面多实例的需求,只能对插件进行修改...而且在改完之后发现修改的工作量很大。

代码是在 demo 的基础上,后端使用 php,删除了不需要的文件,比如其他后端语言处理程序。没有做数据验证和入库等处理,展示页面直接遍历文件夹读取文件。

最终效果图:

初始界面

 

上传图片及刷新页面

文件结构及主要修改文件

 

js

 

server

 

/index.html

<!DOCTYPE HTML>
<!--
/*
 * jQuery File Upload Plugin Demo 9.1.0
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2010, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */
-->
<html lang="en">
<head>
<!-- Force latest IE rendering engine or ChromeFrame if installed -->
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<![endif]-->
<meta charset="utf-8">
<title>jQuery File Upload Demo</title>
<meta name="description" content="File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads and client-side image resizing. Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap styles -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<!-- Generic page styles -->
<link rel="stylesheet" href="css/style.css">
<!-- blueimp Gallery styles -->
<link rel="stylesheet" href="css/blueimp-gallery.min.css">
<!-- CSS to style the file input field as button and adjust the Bootstrap progress bars -->
<link rel="stylesheet" href="css/jquery.fileupload.css">
<!-- <link rel="stylesheet" href="css/jquery.fileupload-ui.css"> -->
<!-- CSS adjustments for browsers with JavaScript disabled -->
<noscript><link rel="stylesheet" href="css/jquery.fileupload-noscript.css"></noscript>
<noscript><link rel="stylesheet" href="css/jquery.fileupload-ui-noscript.css"></noscript>
</head>
<body>
<div class="container">
    <!-- The file upload form used as target for the file upload widget -->
    <form class="fileupload" action="server/php" method="POST" enctype="multipart/form-data">
        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
        <div class="row fileupload-buttonbar">
            <div class="col-lg-7">
                <!-- The fileinput-button span is used to style the file input field as button -->
                <span class="btn btn-primary">食材</span>
                <span class="btn btn-success fileinput-button">
                    <i class="glyphicon glyphicon-plus"></i>
                    <span>Add files...</span>
                    <input type="file" name="food[]" multiple>
                </span>
                <button type="submit" class="btn btn-primary start">
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>Start upload</span>
                </button>
                <button type="reset" class="btn btn-warning cancel">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel upload</span>
                </button>
                <button type="button" class="btn btn-danger delete">
                    <i class="glyphicon glyphicon-trash"></i>
                    <span>Delete</span>
                </button>
                <input type="checkbox" class="toggle">
                <!-- The global file processing state -->
                <span class="fileupload-process"></span>
            </div>
            <!-- The global progress state -->
            <div class="col-lg-5 fileupload-progress fade">
                <!-- The global progress bar -->
                <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
                    <div class="progress-bar progress-bar-success" style="width:0%;"></div>
                </div>
                <!-- The extended global progress state -->
                <div class="progress-extended"> </div>
            </div>
        </div>
        <!-- The table listing the files available for upload/download -->
        <table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>     
    </form> 
    <!-- Multiple File Upload Widgets on the same page -->
    <form class="fileupload" action="server/php" method="POST" enctype="multipart/form-data">
        <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
        <div class="row fileupload-buttonbar">
            <div class="col-lg-7">
                <!-- The fileinput-button span is used to style the file input field as button -->
                <span class="btn btn-primary">配料</span>
                <span class="btn btn-success fileinput-button">
                    <i class="glyphicon glyphicon-plus"></i>
                    <span>Add files...</span>
                    <input type="file" name="batching[]" multiple>
                </span>
                <button type="submit" class="btn btn-primary start">
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>Start upload</span>
                </button>
                <button type="reset" class="btn btn-warning cancel">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel upload</span>
                </button>
                <button type="button" class="btn btn-danger delete">
                    <i class="glyphicon glyphicon-trash"></i>
                    <span>Delete</span>
                </button>
                <input type="checkbox" class="toggle">
                <!-- The global file processing state -->
                <span class="fileupload-process"></span>
            </div>
            <!-- The global progress state -->
            <div class="col-lg-5 fileupload-progress fade">
                <!-- The global progress bar -->
                <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100">
                    <div class="progress-bar progress-bar-success" style="width:0%;"></div>
                </div>
                <!-- The extended global progress state -->
                <div class="progress-extended"> </div>
            </div>
        </div>
        <!-- The table listing the files available for upload/download -->
        <table role="presentation" class="table table-striped"><tbody class="files"></tbody></table>     
    </form> 
</div>
<!-- The blueimp Gallery widget -->
<div id="blueimp-gallery" class="blueimp-gallery blueimp-gallery-controls" data-filter=":even">
    <div class="slides"></div>
    <h3 class="title"></h3>
    <a class="prev">‹</a>
    <a class="next">›</a>
    <a class="close">×</a>
    <a class="play-pause"></a>
    <ol class="indicator"></ol>
</div>
<!-- The template to display files available for upload -->
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-upload fade">
        <td>
            <span class="preview"></span>
        </td>
        <td>
            <p class="name">{%=file.name%}</p>
            <strong class="error text-danger"></strong>
        </td>
        <td>
            <p class="size">Processing...</p>
            <div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="progress-bar progress-bar-success" style="width:0%;"></div></div>
        </td>
        <td>
            {% if (!i && !o.options.autoUpload) { %}
                <button class="btn btn-primary start" disabled>
                    <i class="glyphicon glyphicon-upload"></i>
                    <span>Start</span>
                </button>
            {% } %}
            {% if (!i) { %}
                <button class="btn btn-warning cancel">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel</span>
                </button>
            {% } %}
        </td>
    </tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
    <tr class="template-download fade">
        <td>
            <span class="preview">
                {% if (file.thumbnailUrl) { %}
                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a>
                {% } %}
            </span>
        </td>
        <td>
            <p class="name">
                {% if (file.url) { %}
                    <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?\'data-gallery\':\'\'%}>{%=file.name%}</a>
                {% } else { %}
                    <span>{%=file.name%}</span>
                {% } %}
            </p>
            {% if (file.error) { %}
                <div><span class="label label-danger">Error</span> {%=file.error%}</div>
            {% } %}
        </td>
        <td>
            <span class="size">{%=o.formatFileSize(file.size)%}</span>
        </td>
        <td>
            {% if (file.deleteUrl) { %}
                <button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields=\'{"withCredentials":true}\'{% } %}>
                    <i class="glyphicon glyphicon-trash"></i>
                    <span>Delete</span>
                </button>
                <input type="checkbox" name="delete" value="1" class="toggle">
            {% } else { %}
                <button class="btn btn-warning cancel">
                    <i class="glyphicon glyphicon-ban-circle"></i>
                    <span>Cancel</span>
                </button>
            {% } %}
        </td>
    </tr>
{% } %}
</script>
<script src="js/jquery/1.10.2/jquery.min.js"></script>
<!-- The jQuery UI widget factory, can be omitted if jQuery UI is already included -->
<script src="js/vendor/jquery.ui.widget.js"></script>
<!-- The Templates plugin is included to render the upload/download listings -->
<script src="js/tmpl.min.js"></script>
<!-- The Load Image plugin is included for the preview images and image resizing functionality -->
<script src="js/load-image.all.min.js"></script>
<!-- The Canvas to Blob plugin is included for image resizing functionality -->
<script src="js/canvas-to-blob.min.js"></script>
<!-- Bootstrap JS is not required, but included for the responsive demo navigation -->
<script src="js/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<!-- blueimp Gallery script -->
<script src="js/jquery.blueimp-gallery.min.js"></script>
<!-- The Iframe Transport is required for browsers without support for XHR file uploads -->
<script src="js/jquery.iframe-transport.js"></script>
<!-- The basic File Upload plugin -->
<script src="js/jquery.fileupload.js"></script>
<!-- The File Upload processing plugin -->
<script src="js/jquery.fileupload-process.js"></script>
<!-- The File Upload image preview & resize plugin -->
<script src="js/jquery.fileupload-image.js"></script>
<!-- The File Upload audio preview plugin -->
<script src="js/jquery.fileupload-audio.js"></script>
<!-- The File Upload video preview plugin -->
<script src="js/jquery.fileupload-video.js"></script>
<!-- The File Upload validation plugin -->
<script src="js/jquery.fileupload-validate.js"></script>
<!-- The File Upload user interface plugin -->
<script src="js/jquery.fileupload-ui.js"></script>
<!-- The main application script -->
<script src="js/main.js"></script>
<!-- The XDomainRequest Transport is included for cross-domain file deletion for IE 8 and IE 9 -->
<!--[if (gte IE 8)&(lt IE 10)]>
<script src="js/cors/jquery.xdr-transport.js"></script>
<![endif]-->
</body> 
<script>
    // $(\'.fileupload\').fileupload({
    //     // Uncomment the following to send cross-domain cookies:
    //     //xhrFields: {withCredentials: true},
    //     url: \'server/php/?fields=shirt,sweater\',
    // }); 
    var fields = \'food,batching\';
    $(\'.fileupload\').fileupload({
        url: \'server/php/?fields=\' + fields,
        add: function (e, data) {
            // 不用点击直接上传
            var jqXHR = data.submit()
                .success(function (result, textStatus, jqXHR) {})
                .error(function (jqXHR, textStatus, errorThrown) {})
                .complete(function (result, textStatus, jqXHR) {});
        }     
    });
  
    $.ajax({
        url: \'server/php/?fields=\' + fields,
        success(data) {
            var dataObj = JSON.parse(data);
            $.each(dataObj, function(name, value) {               
                $.each(value, function(k, v){
                    var item = \'<tr class="template-download fade in">\';
                    item += \'<td><span class="preview"><a data-gallery="" download="\' + v.name + \'" title="\' + v.name + \'" href="\' + v.url + \'"><img src="\' + v.thumbnailUrl + \'"></a></span></td><td><p class="name"><a data-gallery="" download="\' + v.name + \'" title="\' + v.url + \'" href="\' + v.url + \'">\' + v.name + \'</a></p></td><td><span class="size">\' + (v.size / 1000) + \' KB</span></td><td>\';
            
                    item += \'<button data-url="\' + v.deleteUrl + \'" data-type="\' + v.deleteType + \'" class="btn btn-danger delete" ><i class="glyphicon glyphicon-trash"></i><span>Delete</span></button>\';
                    item += \' <input type="checkbox" class="toggle" value="1" name="delete"></td></tr>\';

                    var $item = $(item);
                    $input_file = eval($("input[type=\'file\'][name=\'" + name + "[]\']"));
                    $item.appendTo($input_file.parents(\'.fileupload-buttonbar\').siblings(\'.table-striped\').children(\'.files\'));                                         
                });                    
            });                      
        }
    });
</script>
</html>

说明:

通过 fields 来配置文件中不同的文件域,多个文件域的 name 用逗号 , 隔开。这是修改后 demo 中唯一需要根据页面文件域 name 的不同要做配置地方

var fields = \'food,batching\';

  

/js/jquery.fileupload-ui.js

修改 $.widget(\'blueimp.fileupload\', $.blueimp.fileupload, {}) 中 的 getFilesFromResponse

            getFilesFromResponse: function (data) {
                var paramName = JSON.stringify(data.paramName);
                if(paramName) {
                    var files = paramName.slice(2,-4);
                }
                // console.log(files,eval("data.result."+files));
                if (data.result && $.isArray(eval("data.result."+files))) {
                    return eval("data.result."+files);
                }
                return [];
            },

把写死的 files 改成页面中实际的 name

完整文件:

/*
 * jQuery File Upload User Interface Plugin 9.6.0
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2010, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

/* jshint nomen:false */
/* global define, window */

(function (factory) {
    \'use strict\';
    if (typeof define === \'function\' && define.amd) {
        // Register as an anonymous AMD module:
        define([
            \'jquery\',
            \'tmpl\',
            \'./jquery.fileupload-image\',
            \'./jquery.fileupload-audio\',
            \'./jquery.fileupload-video\',
            \'./jquery.fileupload-validate\'
        ], factory);
    } else {
        // Browser globals:
        factory(
            window.jQuery,
            window.tmpl
        );
    }
}(function ($, tmpl) {
    \'use strict\';

    $.blueimp.fileupload.prototype._specialOptions.push(
        \'filesContainer\',
        \'uploadTemplateId\',
        \'downloadTemplateId\'
    );

    // The UI version extends the file upload widget
    // and adds complete user interface interaction:
    $.widget(\'blueimp.fileupload\', $.blueimp.fileupload, {

        options: {
            // By default, files added to the widget are uploaded as soon
            // as the user clicks on the start buttons. To enable automatic
            // uploads, set the following option to true:
            autoUpload: false,
            // The ID of the upload template:
            uploadTemplateId: \'template-upload\',
            // The ID of the download template:
            downloadTemplateId: \'template-download\',
            // The container for the list of files. If undefined, it is set to
            // an element with class "files" inside of the widget element:
            filesContainer: undefined,
            // By default, files are appended to the files container.
            // Set the following option to true, to prepend files instead:
            prependFiles: false,
            // The expected data type of the upload response, sets the dataType
            // option of the $.ajax upload requests:
            dataType: \'json\',
            
            // Error and info messages:
            messages: {
                unknownError: \'Unknown error\'  
            },

            // Function returning the current number of files,
            // used by the maxNumberOfFiles validation:
            getNumberOfFiles: function () {
                return this.filesContainer.children()
                    .not(\'.processing\').length;
            },

            // Callback to retrieve the list of files from the server response:
            getFilesFromResponse: function (data) {
                var paramName = JSON.stringify(data.paramName);
                if(paramName) {
                    var files = paramName.slice(2,-4);
                }
                // console.log(files,eval("data.result."+files));
                if (data.result && $.isArray(eval("data.result."+files))) {
                    return eval("data.result."+files);
                }
                return [];
            },

            // The add callback is invoked as soon as files are added to the fileupload
            // widget (via file input selection, drag & drop or add API call).
            // See the basic file upload widget for more information:
            add: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var $this = $(this),
                    that = $this.data(\'blueimp-fileupload\') ||
                        $this.data(\'fileupload\'),
                    options = that.options;
                data.context = that._renderUpload(data.files)
                    .data(\'data\', data)
                    .addClass(\'processing\');
                options.filesContainer[
                    options.prependFiles ? \'prepend\' : \'append\'
                ](data.context);
                that._forceReflow(data.context);
                that._transition(data.context);
                data.process(function () {
                    return $this.fileupload(\'process\', data);
                }).always(function () {
                    data.context.each(function (index) {
                        $(this).find(\'.size\').text(
                            that._formatFileSize(data.files[index].size)
                        );
                    }).removeClass(\'processing\');
                    that._renderPreviews(data);
                }).done(function () {
                    data.context.find(\'.start\').prop(\'disabled\', false);
                    if ((that._trigger(\'added\', e, data) !== false) &&
                            (options.autoUpload || data.autoUpload) &&
                            data.autoUpload !== false) {
                        data.submit();
                    }
                }).fail(function () {
                    if (data.files.error) {
                        data.context.each(function (index) {
                            var error = data.files[index].error;
                            if (error) {
                                $(this).find(\'.error\').text(error);
                            }
                        });
                    }
                });
            },
            // Callback for the start of each file upload request:
            send: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var that = $(this).data(\'blueimp-fileupload\') ||
                        $(this).data(\'fileupload\');
                if (data.context && data.dataType &&
                        data.dataType.substr(0, 6) === \'iframe\') {
                    // Iframe Transport does not support progress events.
                    // In lack of an indeterminate progress bar, we set
                    // the progress to 100%, showing the full animated bar:
                    data.context
                        .find(\'.progress\').addClass(
                            !$.support.transition && \'progress-animated\'
                        )
                        .attr(\'aria-valuenow\', 100)
                        .children().first().css(
                            \'width\',
                            \'100%\'
                        );
                }
                return that._trigger(\'sent\', e, data);
            },
            // Callback for successful uploads:
            done: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var that = $(this).data(\'blueimp-fileupload\') ||
                        $(this).data(\'fileupload\'),
                    getFilesFromResponse = data.getFilesFromResponse ||
                        that.options.getFilesFromResponse,
                    files = getFilesFromResponse(data),
                    template,
                    deferred;
                if (data.context) {
                    data.context.each(function (index) {
                        var file = files[index] ||
                                {error: \'Empty file upload result\'};
                        deferred = that._addFinishedDeferreds();
                        that._transition($(this)).done(
                            function () {
                                var node = $(this);
                                template = that._renderDownload([file])
                                    .replaceAll(node);
                                that._forceReflow(template);
                                that._transition(template).done(
                                    function () {
                                        data.context = $(this);
                                        that._trigger(\'completed\', e, data);
                                        that._trigger(\'finished\', e, data);
                                        deferred.resolve();
                                    }
                                );
                            }
                        );
                    });
                } else {
                    template = that._renderDownload(files)[
                        that.options.prependFiles ? \'prependTo\' : \'appendTo\'
                    ](that.options.filesContainer);
                    that._forceReflow(template);
                    deferred = that._addFinishedDeferreds();
                    that._transition(template).done(
                        function () {
                            data.context = $(this);
                            that._trigger(\'completed\', e, data);
                            that._trigger(\'finished\', e, data);
                            deferred.resolve();
                        }
                    );
                }
            },
            // Callback for failed (abort or error) uploads:
            fail: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var that = $(this).data(\'blueimp-fileupload\') ||
                        $(this).data(\'fileupload\'),
                    template,
                    deferred;                
                if (data.context) {
                    data.context.each(function (index) {
                        if (data.errorThrown !== \'abort\') {
                            var file = data.files[index];
                            file.error = file.error || data.errorThrown ||
                                data.i18n(\'unknownError\');
                            deferred = that._addFinishedDeferreds();
                            that._transition($(this)).done(
                                function () {
                                    var node = $(this);
                                    template = that._renderDownload([file])
                                        .replaceAll(node);
                                    that._forceReflow(template);
                                    that._transition(template).done(
                                        function () {
                                            data.context = $(this);
                                            that._trigger(\'failed\', e, data);
                                            that._trigger(\'finished\', e, data);
                                            deferred.resolve();
                                        }
                                    );
                                }
                            );
                        } else {
                            deferred = that._addFinishedDeferreds();
                            that._transition($(this)).done(
                                function () {
                                    $(this).remove();
                                    that._trigger(\'failed\', e, data);
                                    that._trigger(\'finished\', e, data);
                                    deferred.resolve();
                                }
                            );
                        }
                    });
                } else if (data.errorThrown !== \'abort\') {
                    data.context = that._renderUpload(data.files)[
                        that.options.prependFiles ? \'prependTo\' : \'appendTo\'
                    ](that.options.filesContainer)
                        .data(\'data\', data);
                    that._forceReflow(data.context);
                    deferred = that._addFinishedDeferreds();
                    that._transition(data.context).done(
                        function () {
                            data.context = $(this);
                            that._trigger(\'failed\', e, data);
                            that._trigger(\'finished\', e, data);
                            deferred.resolve();
                        }
                    );
                } else {
                    that._trigger(\'failed\', e, data);
                    that._trigger(\'finished\', e, data);
                    that._addFinishedDeferreds().resolve();
                }
            },
            // Callback for upload progress events:
            progress: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var progress = Math.floor(data.loaded / data.total * 100);
                if (data.context) {
                    data.context.each(function () {
                        $(this).find(\'.progress\')
                            .attr(\'aria-valuenow\', progress)
                            .children().first().css(
                                \'width\',
                                progress + \'%\'
                            );
                    });
                }
            },
            // Callback for global upload progress events:
            progressall: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var $this = $(this),
                    progress = Math.floor(data.loaded / data.total * 100),
                    globalProgressNode = $this.find(\'.fileupload-progress\'),
                    extendedProgressNode = globalProgressNode
                        .find(\'.progress-extended\');
                if (extendedProgressNode.length) {
                    extendedProgressNode.html(
                        ($this.data(\'blueimp-fileupload\') || $this.data(\'fileupload\'))
                            ._renderExtendedProgress(data)
                    );
                }
                globalProgressNode
                    .find(\'.progress\')
                    .attr(\'aria-valuenow\', progress)
                    .children().first().css(
                        \'width\',
                        progress + \'%\'
                    );
            },
            // Callback for uploads start, equivalent to the global ajaxStart event:
            start: function (e) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var that = $(this).data(\'blueimp-fileupload\') ||
                        $(this).data(\'fileupload\');
                that._resetFinishedDeferreds();
                that._transition($(this).find(\'.fileupload-progress\')).done(
                    function () {
                        that._trigger(\'started\', e);
                    }
                );
            },
            // Callback for uploads stop, equivalent to the global ajaxStop event:
            stop: function (e) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                var that = $(this).data(\'blueimp-fileupload\') ||
                        $(this).data(\'fileupload\'),
                    deferred = that._addFinishedDeferreds();
                $.when.apply($, that._getFinishedDeferreds())
                    .done(function () {
                        that._trigger(\'stopped\', e);
                    });
                that._transition($(this).find(\'.fileupload-progress\')).done(
                    function () {
                        $(this).find(\'.progress\')
                            .attr(\'aria-valuenow\', \'0\')
                            .children().first().css(\'width\', \'0%\');
                        $(this).find(\'.progress-extended\').html(\' \');
                        deferred.resolve();
                    }
                );
            },
            processstart: function (e) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                $(this).addClass(\'fileupload-processing\');
            },
            processstop: function (e) {
                if (e.isDefaultPrevented()) {
                    return false;
                }
                $(this).removeClass(\'fileupload-processing\');
            },
            // Callback for file deletion:
            destroy: function (e, data) {
                if (e.isDefaultPrevented()) {
                    return false;
                }        
                var that = $(this).data(\'blueimp-fileupload\') ||
                        $(this).data(\'fileupload\'),
                    removeNode = function () {
                        that._transition(data.context).done(
                            function () {
                                $(this).remove();
                                that._trigger(\'destroyed\', e, data);
                            }
                        );
                    };
                if (data.url) {
                    data.dataType = data.dataType || that.options.dataType;
                    $.ajax(data).done(removeNode).fail(function () {
                        that._trigger(\'destroyfailed\', e, data);
                    });
                } else {
                    removeNode();
                }
            }
        },

        _resetFinishedDeferreds: function () {
            this._finishedUploads = [];
        },

        _addFinishedDeferreds: function (deferred) {
            if (!deferred) {
                deferred = $.Deferred();
            }
            this._finishedUploads.push(deferred);
            return deferred;
        },

        _getFinishedDeferreds: function () {
            return this._finishedUploads;
        },

        // Link handler, that allows to download files
        // by drag & drop of the links to the desktop:
        _enableDragToDesktop: function () {
            var link = $(this),
                url = link.prop(\'href\'),
                name = link.prop(\'download\'),
                type = \'application/octet-stream\';
            link.bind(\'dragstart\', function (e) {
                try {
                    e.originalEvent.dataTransfer.setData(
                        \'DownloadURL\',
                        [type, name, url].join(\':\')
                    );
                } catch (ignore) {}
            });
        },

        _formatFileSize: function (bytes) {
            if (typeof bytes !== \'number\') {
                return \'\';
            }
            if (bytes >= 1000000000) {
                return (bytes / 1000000000).toFixed(2) + \' GB\';
            }
            if (bytes >= 1000000) {
                return (bytes / 1000000).toFixed(2) + \' MB\';
            }
            return (bytes / 1000).toFixed(2) + \' KB\';
        },

        _formatBitrate: function (bits) {
            if (typeof bits !== \'number\') {
                return \'\';
            }
            if (bits >= 1000000000) {
                return (bits / 1000000000).toFixed(2) + \' Gbit/s\';
            }
            if (bits >= 1000000) {
                return (bits / 1000000).toFixed(2) + \' Mbit/s\';
            }
            if (bits >= 1000) {
                return (bits / 1000).toFixed(2) + \' kbit/s\';
            }
            return bits.toFixed(2) + \' bit/s\';
        },

        _formatTime: function (seconds) {
            var date = new Date(seconds * 1000),
                days = Math.floor(seconds / 86400);
            days = days ? days + \'d \' : \'\';
            return days +
                (\'0\' + date.getUTCHours()).slice(-2) + \':\' +
                (\'0\' + date.getUTCMinutes()).slice(-2) + \':\' +
                (\'0\' + date.getUTCSeconds()).slice(-2);
        },

        _formatPercentage: function (floatValue) {
            return (floatValue * 100).toFixed(2) + \' %\';
        },

        _renderExtendedProgress: function (data) {
            return this._formatBitrate(data.bitrate) + \' | \' +
                this._formatTime(
                    (data.total - data.loaded) * 8 / data.bitrate
                ) + \' | \' +
                this._formatPercentage(
                    data.loaded / data.total
                ) + \' | \' +
                this._formatFileSize(data.loaded) + \' / \' +
                this._formatFileSize(data.total);
        },

        _renderTemplate: function (func, files) {
            if (!func) {
                return $();
            }
            var result = func({
                files: files,
                formatFileSize: this._formatFileSize,
                options: this.options
            });
            if (result instanceof $) {
                return result;
            }
            return $(this.options.templatesContainer).html(result).children();
        },

        _renderPreviews: function (data) {         
            data.context.find(\'.preview\').each(function (index, elm) {
                $(elm).append(data.files[index].preview);
            });
        },

        _renderUpload: function (files) {
            return this._renderTemplate(
                this.options.uploadTemplate,
                files
            );
        },

        _renderDownload: function (files) {
            return this._renderTemplate(
                this.options.downloadTemplate,
                files
            ).find(\'a[download]\').each(this._enableDragToDesktop).end();
        },

        _startHandler: function (e) {
            e.preventDefault();
            var button = $(e.currentTarget),
                template = button.closest(\'.template-upload\'),
                data = template.data(\'data\');
            button.prop(\'disabled\', true);
            if (data && data.submit) {
                data.submit();
            }
        },

        _cancelHandler: function (e) {
            e.preventDefault();
            var template = $(e.currentTarget)
                    .closest(\'.template-upload,.template-download\'),
                data = template.data(\'data\') || {};
            data.context = data.context || template;
            if (data.abort) {
                data.abort();
            } else {
                data.errorThrown = \'abort\';
                this._trigger(\'fail\', e, data);
            }
        },

        _deleteHandler: function (e) {
            e.preventDefault();
            var button = $(e.currentTarget);
            this._trigger(\'destroy\', e, $.extend({
                context: button.closest(\'.template-download\'),
                type: \'DELETE\'
            }, button.data()));
        },

        _forceReflow: function (node) {
            return $.support.transition && node.length &&
                node[0].offsetWidth;
        },

        _transition: function (node) {
            var dfd = $.Deferred();
            if ($.support.transition && node.hasClass(\'fade\') && node.is(\':visible\')) {
                node.bind(
                    $.support.transition.end,
                    function (e) {
                        // Make sure we don\'t respond to other transitions events
                        // in the container element, e.g. from button elements:
                        if (e.target === node[0]) {
                            node.unbind($.support.transition.end);
                            dfd.resolveWith(node);
                        }
                    }
                ).toggleClass(\'in\');
            } else {
                node.toggleClass(\'in\');
                dfd.resolveWith(node);
            }
            return dfd;
        },

        _initButtonBarEventHandlers: function () {
            var fileUploadButtonBar = this.element.find(\'.fileupload-buttonbar\'),
                filesList = this.options.filesContainer;
            this._on(fileUploadButtonBar.find(\'.start\'), {
                click: function (e) {
                    e.preventDefault();
                    filesList.find(\'.start\').click();
                }
            });
            this._on(fileUploadButtonBar.find(\'.cancel\'), {
                click: function (e) {
                    e.preventDefault();
                    filesList.find(\'.cancel\').click();
                }
            });
            this._on(fileUploadButtonBar.find(\'.delete\'), {
                click: function (e) {
                    e.preventDefault();
                    filesList.find(\'.toggle:checked\')
                        .closest(\'.template-download\')
                        .find(\'.delete\').click();
                    fileUploadButtonBar.find(\'.toggle\')
                        .prop(\'checked\', false);
                }
            });
            this._on(fileUploadButtonBar.find(\'.toggle\'), {
                change: function (e) {
                    filesList.find(\'.toggle\').prop(
                        \'checked\',
                        $(e.currentTarget).is(\':checked\')
                    );
                }
            });
        },

        _destroyButtonBarEventHandlers: function () {
            this._off(
                this.element.find(\'.fileupload-buttonbar\')
                    .find(\'.start, .cancel, .delete\'),
                \'click\'
            );
            this._off(
                this.element.find(\'.fileupload-buttonbar .toggle\'),
                \'change.\'
            );
        },

        _initEventHandlers: function () {
            this._super();
            this._on(this.options.filesContainer, {
                \'click .start\': this._startHandler,
                \'click .cancel\': this._cancelHandler,
                \'click .delete\': this._deleteHandler
            });
            this._initButtonBarEventHandlers();
        },

        _destroyEventHandlers: function () {
            this._destroyButtonBarEventHandlers();
            this._off(this.options.filesContainer, \'click\');
            this._super();
        },

        _enableFileInputButton: function () {
            this.element.find(\'.fileinput-button input\')
                .prop(\'disabled\', false)
                .parent().removeClass(\'disabled\');
        },

        _disableFileInputButton: function () {
            this.element.find(\'.fileinput-button input\')
                .prop(\'disabled\', true)
                .parent().addClass(\'disabled\');
        },

        _initTemplates: function () {
            var options = this.options;
            options.templatesContainer = this.document[0].createElement(
                options.filesContainer.prop(\'nodeName\')
            );
            if (tmpl) {
                if (options.uploadTemplateId) {
                    options.uploadTemplate = tmpl(options.uploadTemplateId);
                }
                if (options.downloadTemplateId) {
                    options.downloadTemplate = tmpl(options.downloadTemplateId);
                }
            }
        },

        _initFilesContainer: function () {
            var options = this.options;
            if (options.filesContainer === undefined) {
                options.filesContainer = this.element.find(\'.files\');
            } else if (!(options.filesContainer instanceof $)) {
                options.filesContainer = $(options.filesContainer);
            }
        },

        _initSpecialOptions: function () {
            this._super();
            this._initFilesContainer();
            this._initTemplates();
        },

        _create: function () {
            this._super();
            this._resetFinishedDeferreds();
            if (!$.support.fileInput) {
                this._disableFileInputButton();
            }
        },

        enable: function () {
            var wasDisabled = false;
            if (this.options.disabled) {
                wasDisabled = true;
            }
            this._super();
            if (wasDisabled) {
                this.element.find(\'input, button\').prop(\'disabled\', false);
                this._enableFileInputButton();
            }
        },

        disable: function () {
            if (!this.options.disabled) {
                this.element.find(\'input, button\').prop(\'disabled\', true);
                this._disableFileInputButton();
            }
            this._super();
        }

    });

}));

  

./js/main.js

注释以下代码

    $(\'.fileupload\').fileupload({
        // Uncomment the following to send cross-domain cookies:
        //xhrFields: {withCredentials: true},
        url: \'server/php/\'
    });

移至 ./index.html 中

 

./server/php/index.php

<?php
/*
 * jQuery File Upload Plugin PHP Example 5.14
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2010, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

error_reporting(E_ALL | E_STRICT);
require(\'UploadHandler.php\');

// 添加图片
if(! empty($_FILES)) {
	$keys = array_keys($_FILES);
	if(! empty($keys)) {
		$key = $keys[0];
	} else {
		$key = null;
	}
} else {
	// 删除图片时的参数
	$pathinfo = pathinfo($_SERVER[\'REQUEST_URI\']);
	if(! empty($pathinfo[\'filename\'])) {
		$dirname = preg_match(\'/^\\?(.*)=.*$/\', $pathinfo[\'filename\'], $match);
		if(! empty($match[1]) && $match[1] != \'fields\') {
			$key = $match[1];
		} else {
			$key = null;
		}
	}	else {
		$key = null;
	}
}

$upload_handler = new UploadHandler($key);

根据不同的添加/删除的不同情况,传递不同的参数,同时在页面加载时通过 ajax 获取不同文件夹的文件用于展示(并没有做多层目录或者文件存储目录与文件域的 name 不同的情况的考虑,同时实际项目的 url 模式也有可能与程序中的正则表达式不匹配,可在实际项目中根据实际情况修改)

 

./server/php/UploadHandler.php 上传类

修改了 $this->options 中关于上传路径的参数,原 demo 中是写死的

    function __construct($dir = null, $options = null, $initialize = true, $error_messages = null) {
        if($dir === null) {
            $dir = \'files\';
        }
        $this->options = array(
            \'script_url\' => $this->get_full_url().\'/\',
            \'upload_dir\' => dirname($this->get_server_var(\'SCRIPT_FILENAME\')).\'/\'.$dir.\'/\',
            \'upload_url\' => $this->get_full_url().\'/\'.$dir.\'/\',
            \'user_dirs\' => false,
            \'mkdir_mode\' => 0755,
            \'param_name\' => $dir,
            ..........

  

修改了 get_singular_param_name 方法

    protected function get_singular_param_name() {
        // return substr($this->options[\'param_name\'], 0, -1);
        return $this->options[\'param_name\'];
    }

 

修改了 get 方法

    public function get($print_response = true) {
        if ($print_response && isset($_GET[\'download\'])) {
            return $this->download();
        }

        if(isset($_GET[\'fields\']) && $_GET[\'fields\'] != \'\') {
            $fields = $_GET[\'fields\'];
            if(strpos($fields, \',\') === false) { // 只有一个实例
                $this->options[\'upload_dir\'] = dirname($this->get_server_var(\'SCRIPT_FILENAME\')).\'/\'.$fields.\'/\';
                $this->options[\'upload_url\'] = $this->get_full_url().\'/\'.$fields.\'/\';
                $this->options[\'param_name\'] = $fields;

                $response = array(
                    $val => $this->get_file_objects()
                );
                $return = $this->generate_response($response, $print_response);
            } else { // 多个实例
                $fields = explode(\',\', $fields);
                $return = array();
                foreach($fields as $key => $val) {

                    $this->options[\'upload_dir\'] = dirname($this->get_server_var(\'SCRIPT_FILENAME\')).\'/\'.$val.\'/\';
                    $this->options[\'upload_url\'] = $this->get_full_url().\'/\'.$val.\'/\';
                    $this->options[\'param_name\'] = $val;

                    $response = $this->get_file_objects();
                    if(! empty($response)) {
                        $return[$val] = $response;
                    }
                } 
            }
            echo json_encode($return);
        }
    }

get 方法主要用于刷新页面后展示之前的上传列表,这个只是最简单的实现,实际项目中应该是通过数据库查找

完整文件:

<?php
/*
 * jQuery File Upload Plugin PHP Class 8.1.0
 * https://github.com/blueimp/jQuery-File-Upload
 *
 * Copyright 2010, Sebastian Tschan
 * https://blueimp.net
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/MIT
 */

class UploadHandler
{

    protected $options;

    // PHP File Upload error message codes:
    // http://php.net/manual/en/features.file-upload.errors.php
    protected $error_messages = array(
        1 => \'The uploaded file exceeds the upload_max_filesize directive in php.ini\',
        2 => \'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form\',
        3 => \'The uploaded file was only partially uploaded\',
        4 => \'No file was uploaded\',
        6 => \'Missing a temporary folder\',
        7 => \'Failed to write file to disk\',
        8 => \'A PHP extension stopped the file upload\',
        \'post_max_size\' => \'The uploaded file exceeds the post_max_size directive in php.ini\',
        \'max_file_size\' => \'File is too big\',
        \'min_file_size\' => \'File is too small\',
        \'accept_file_types\' => \'Filetype not allowed\',
        \'max_number_of_files\' => \'Maximum number of files exceeded\',
        \'max_width\' => \'Image exceeds maximum width\',
        \'min_width\' => \'Image requires a minimum width\',
        \'max_height\' => \'Image exceeds maximum height\',
        \'min_height\' => \'Image requires a minimum height\',
        \'abort\' => \'File upload aborted\',
        \'image_resize\' => \'Failed to resize image\'
    );

    protected $image_objects = array();

    function __construct($dir = null, $options = null, $initialize = true, $error_messages = null) {
        if($dir === null) {
            $dir = \'files\';
        }
        $this->options = array(
            \'script_url\' => $this->get_full_url().\'/\',
            \'upload_dir\' => dirname($this->get_server_var(\'SCRIPT_FILENAME\')).\'/\'.$dir.\'/\',
            \'upload_url\' => $this->get_full_url().\'/\'.$dir.\'/\',
            \'user_dirs\' => false,
            \'mkdir_mode\' => 0755,
            \'param_name\' => $dir,
            // Set the following option to \'POST\', if your server does not support
            // DELETE requests. This is a parameter sent to the client:
            \'delete_type\' => \'DELETE\',
            \'access_control_allow_origin\' => \'*\',
            \'access_control_allow_credentials\' => false,
            \'access_control_allow_methods\' => array(
                \'OPTIONS\',
                \'HEAD\',
                \'GET\',
                \'POST\',
                \'PUT\',
                \'PATCH\',
                \'DELETE\'
            ),
            \'access_control_allow_headers\' => array(
                \'Content-Type\',
                \'Content-Range\',
                \'Content-Disposition\'
            ),
            // Enable to provide file downloads via GET requests to the PHP script:
            //     1. Set to 1 to download files via readfile method through PHP
            //     2. Set to 2 to send a X-Sendfile header for lighttpd/Apache
            //     3. Set to 3 to send a X-Accel-Redirect header for nginx
            // If set to 2 or 3, adjust the upload_url option to the base path of
            // the redirect parameter, e.g. \'/files/\'.
            \'download_via_php\' => false,
            // Read files in chunks to avoid memory limits when download_via_php
            // is enabled, set to 0 to disable chunked reading of files:
            \'readfile_chunk_size\' => 10 * 1024 * 1024, // 10 MiB
            // Defines which files can be displayed inline when downloaded:
            \'inline_file_types\' => \'/\\.(gif|jpe?g|png)$/i\',
            // Defines which files (based on their names) are accepted for upload:
            \'accept_file_types\' => \'/.+$/i\',
            // The php.ini settings upload_max_filesize and post_max_size
            // take precedence over the following max_file_size setting:
            \'max_file_size\' => null,
            \'min_file_size\' => 1,
            // The maximum number of files for the upload directory:
            \'max_number_of_files\' => null,
            // Defines which files are handled as image files:
            \'image_file_types\' => \'/\\.(gif|jpe?g|png)$/i\',
            // Use exif_imagetype on all files to correct file extensions:
            \'correct_image_extensions\' => false,
            // Image resolution restrictions:
            \'max_width\' => null,
            \'max_height\' => null,
            \'min_width\' => 1,
            \'min_height\' => 1,
            // Set the following option to false to enable resumable uploads:
            \'discard_aborted_uploads\' => true,
            // Set to 0 to use the GD library to scale and orient images,
            // set to 1 to use imagick (if installed, falls back to GD),
            // set to 2 to use the ImageMagick convert binary directly:
            \'image_library\' => 1,
            // Uncomment the following to define an array of resource limits
            // for imagick:
            /*
            \'imagick_resource_limits\' => array(
                imagick::RESOURCETYPE_MAP => 32,
                imagick::RESOURCETYPE_MEMORY => 32
            ),
            */
            // Command or path for to the ImageMagick convert binary:
            \'convert_bin\' => \'convert\',
            // Uncomment the following to add parameters in front of each
            // ImageMagick convert call (the limit constraints seem only
            // to have an effect if put in front):
            /*
            \'convert_params\' => \'-limit memory 32MiB -limit map 32MiB\',
            */
            // Command or path for to the ImageMagick identify binary:
            \'identify_bin\' => \'identify\',
            \'image_versions\' => array(
                // The empty image version key defines options for the original image:
                \'\' => array(
                    // Automatically rotate images based on EXIF meta data:
                    \'auto_orient\' => true
                ),
                // Uncomment the following to create medium sized images:
                /*
                \'medium\' => array(
                    \'max_width\' => 800,
                    \'max_height\' => 600
                ),
                */
                \'thumbnail\' => array(
                    // Uncomment the following to use a defined directory for the thumbnails
                    // instead of a subdirectory based on the version identifier.
                    // Make sure that this directory doesn\'t allow execution of files if you
                    // don\'t pose any restrictions on the type of uploaded files, e.g. by
                    // copying the .htaccess file from the files directory for Apache:
                    //\'upload_dir\' => dirname($this->get_server_var(\'SCRIPT_FILENAME\')).\'/thumb/\',
                    //\'upload_url\' => $this->get_full_url().\'/thumb/\',
                    // Uncomment the following to force the max
                    // dimensions and e.g. create square thumbnails:
                    //\'crop\' => true,
                    \'max_width\' => 80,
                    \'max_height\' => 80
                )
            )
        );

        if ($options) {
            $this->options = $options + $this->options;
        }
        if ($error_messages) {
            $this->error_messages = $error_messages + $this->error_messages;
        }
        if ($initialize) {
            $this->initialize();
        }
    }

    protected function initialize() {
        switch ($this->get_server_var(\'REQUEST_METHOD\')) {
            case \'OPTIONS\':
            case \'HEAD\':
                $this->head();
                break;
            case \'GET\':
                $this->get();
                break;
            case \'PATCH\':
            case \'PUT\':
            case \'POST\':
                $this->post();
                break;
            case \'DELETE\':
                $this->delete();
                break;
            default:
                $this->header(\'HTTP/1.1 405 Method Not Allowed\');
        }
    }

    protected function get_full_url() {
        $https = !empty($_SERVER[\'HTTPS\']) && strcasecmp($_SERVER[\'HTTPS\'], \'on\') === 0 ||
            !empty($_SERVER[\'HTTP_X_FORWARDED_PROTO\']) &&
                strcasecmp($_SERVER[\'HTTP_X_FORWARDED_PROTO\'], \'https\') === 0;
        return
            ($https ? \'https://\' : \'http://\').
            (!empty($_SERVER[\'REMOTE_USER\']) ? $_SERVER[\'REMOTE_USER\'].\'@\' : \'\').
            (isset($_SERVER[\'HTTP_HOST\']) ? $_SERVER[\'HTTP_HOST\'] : ($_SERVER[\'SERVER_NAME\'].
            ($https && $_SERVER[\'SERVER_PORT\'] === 443 ||
            $_SERVER[\'SERVER_PORT\'] === 80 ? \'\' : \':\'.$_SERVER[\'SERVER_PORT\']))).
            substr($_SERVER[\'SCRIPT_NAME\'],0, strrpos($_SERVER[\'SCRIPT_NAME\'], \'/\'));
    }

    protected function get_user_id() {
        @session_start();
        return session_id();
    }

    protected function get_user_path() {
        if ($this->options[\'user_dirs\']) {
            return $this->get_user_id().\'/\';
        }
        return \'\';
    }

    protected function get_upload_path($file_name = null, $version = null) {
        $file_name = $file_name ? $file_name : \'\';
        if (empty($version)) {
            $version_path = \'\';
        } else {
            $version_dir = @$this->options[\'image_versions\'][$version][\'upload_dir\'];
            if ($version_dir) {
                return $version_dir.$this->get_user_path().$file_name;
            }
            $version_path = $version.\'/\';
        }
        return $this->options[\'upload_dir\'].$this->get_user_path()
            .$version_path.$file_name;
    }

    protected function get_query_separator($url) {
        return strpos($url, \'?\') === false ? \'?\' : \'&\';
    }

    protected function get_download_url($file_name, $version = null, $direct = false) {
        if (!$direct && $this->options[\'download_via_php\']) {
            $url = $this->options[\'script_url\']
                .$this->get_query_separator($this->options[\'script_url\'])
                .$this->get_singular_param_name()
                .\'=\'.rawurlencode($file_name);
            if ($version) {
                $url .= \'&version=\'.rawurlencode($version);
            }
            return $url.\'&download=1\';
        }
        if (empty($version)) {
            $version_path = \'\';
        } else {
            $version_url = @$this->options[\'image_versions\'][$version][\'upload_url\'];
            if ($version_url) {
                return $version_url.$this->get_user_path().rawurlencode($file_name);
            }
            $version_path = rawurlencode($version).\'/\';
        }
        return $this->options[\'upload_url\'].$this->get_user_path()
            .$version_path.rawurlencode($file_name);
    }

    protected function set_additional_file_properties($file) {
        $file->deleteUrl = $this->options[\'script_url\']
            .$this->get_query_separator($this->options[\'script_url\'])
            .$this->get_singular_param_name()
            .\'=\'.rawurlencode($file->name);
        $file->deleteType = $this->options[\'delete_type\'];
        if ($file->deleteType !== \'DELETE\') {
            $file->deleteUrl .= \'&_method=DELETE\';
        }
        if ($this->options[\'access_control_allow_credentials\']) {
            $file->deleteWithCredentials = true;
        }
    }

    // Fix for overflowing signed 32 bit integers,
    // works for sizes up to 2^32-1 bytes (4 GiB - 1):
    protected function fix_integer_overflow($size) {
        if ($size < 0) {
            $size += 2.0 * (PHP_INT_MAX + 1);
        }
        return $size;
    }

    protected function get_file_size($file_path, $clear_stat_cache = false) {
        if ($clear_stat_cache) {
            if (version_compare(PHP_VERSION, \'5.3.0\') >= 0) {
                clearstatcache(true, $file_path);
            } else {
                clearstatcache();
            }
        }
        return $this->fix_integer_overflow(filesize($file_path));
    }

    protected function is_valid_file_object($file_name) {
        $file_path = $this->get_upload_path($file_name);
        if (is_file($file_path) && $file_name[0] !== \'.\') {
            return true;
        }
        return false;
    }

    protected function get_file_object($file_name) {
        if ($this->is_valid_file_object($file_name)) {
            $file = new \\stdClass();
            $file->name = $file_name;
            $file->size = $this->get_file_size(
                

以上是关于jQuery File Upload 单页面多实例的实现的主要内容,如果未能解决你的问题,请参考以下文章

jQuery File Upload文件上传插件使用

jQuery File Upload 图片上传解决方案兼容IE6+

我用jQuery-File-Upload 做上传的时候,点击按钮的时候,就刷新一下页面,不弹出窗口,怎么做呀?

前端开发:功能强大的jQuery文件上传插件(jQuery File Upload)

jquery ajaxfileupload为啥会刷新页面

Spring-boot之jQuery File Upload后台配置方法