zoukankan      html  css  js  c++  java
  • jQuery file upload cropper的 click .preview事件没有绑定成功

    测试

    修改https://github.com/tkvw/jQuery-File-Upload/blob/master/basic-plus.html

    var node = $('<p id="chuck" class="preview"/>')
    .append($('<span/>').text(file.name));

    给p增加id和class,在页面加载后,

    打开浏览器的console,然后手动执行,然后单击图片。会发现这个事件是会触发的

    $(".preview").on("click", function(){
    alert("test");
    })

    但是jquery.fileupload-image-editor.js中的没有触发,事件应该是绑定了

    手动移除事件

    $(".preview").off("click");  https://stackoverflow.com/questions/209029/best-way-to-remove-an-event-handler-in-jquery

    分析

    1.jquery.fileupload-image-editor.js定义了uploadImageEditorPreviewSelector

    uploadImageEditorPreviewSelector: 'click .preview',

    2,.jquery.fileupload-ui.js中定义了filesContainer
    // 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,

    _initEventHandlers: function () {
    this._super();

    var handlers = {};
    handlers[this.options.uploadImageEditorPreviewSelector] = this._previewHandler.bind(this);

    this._on(this.options.filesContainer, handlers);
    },

    文件上传之后

     jquery.fileupload.js中_onAdd: function (e, data) {

    that._initResponseObject(newData);
    that._initProgressObject(newData);
    that._addConvenienceMethods(e, newData);
    result = that._trigger(
    'add',
    $.Event('add', {delegatedEvent: e}),
    newData
    );
    return result;

    _initResponseObject: function (obj) {
    var prop;
    if (obj._response) {
    for (prop in obj._response) {
    if (obj._response.hasOwnProperty(prop)) {
    delete obj._response[prop];
    }
    }
    } else {
    obj._response = {};
    }
    },

    _initProgressObject: function (obj) {
    var progress = {
    loaded: 0,
    total: 0,
    bitrate: 0
    };
    if (obj._progress) {
    $.extend(obj._progress, progress);
    } else {
    obj._progress = progress;
    }
    },

     // Adds convenience methods to the data callback argument:
            _addConvenienceMethods: function (e, data) {
                var that = this,
                    getPromise = function (args) {
                        return $.Deferred().resolveWith(that, args).promise();
                    };
                data.process = function (resolveFunc, rejectFunc) {
                    if (resolveFunc || rejectFunc) {
                        data._processQueue = this._processQueue =
                            (this._processQueue || getPromise([this])).then(
                                function () {
                                    if (data.errorThrown) {
                                        return $.Deferred()
                                            .rejectWith(that, [data]).promise();
                                    }
                                    return getPromise(arguments);
                                }
                            ).then(resolveFunc, rejectFunc);
                    }
                    return this._processQueue || getPromise([this]);
                };
                data.submit = function () {
                    if (this.state() !== 'pending') {
                        data.jqXHR = this.jqXHR =
                            (that._trigger(
                                'submit',
                                $.Event('submit', {delegatedEvent: e}),
                                this
                            ) !== false) && that._onSend(e, this);
                    }
                    return this.jqXHR || that._getXHRPromise();
                };
                data.abort = function () {
                    if (this.jqXHR) {
                        return this.jqXHR.abort();
                    }
                    this.errorThrown = 'abort';
                    that._trigger('fail', null, this);
                    return that._getXHRPromise(false);
                };
                data.state = function () {
                    if (this.jqXHR) {
                        return that._getDeferredState(this.jqXHR);
                    }
                    if (this._processQueue) {
                        return that._getDeferredState(this._processQueue);
                    }
                };
                data.processing = function () {
                    return !this.jqXHR && this._processQueue && that
                        ._getDeferredState(this._processQueue) === 'pending';
                };
                data.progress = function () {
                    return this._progress;
                };
                data.response = function () {
                    return this._response;
                };
            },

    jquery.ui.widget.js里面的_trigger函数

    this.element.trigger( event, data );

    打印event

    jQuery.Event {originalEvent: j…y.Event, type: "fileuploadadd", isDefaultPrevented: ƒ, timeStamp: 1561917127348, jQuery111304105261403454039: true, …}currentTarget: input#fileuploaddata: undefineddelegateTarget: input#fileuploaddelegatedEvent: jQuery.Event {originalEvent: Event, type: "change", isDefaultPrevented: ƒ, timeStamp: 33359.854999987874, jQuery111304105261403454039: true, …}handleObj: {type: "fileuploadadd", origType: "fileuploadadd", data: undefined, handler: ƒ, guid: 20, …}isDefaultPrevented: ƒ returnFalse()isTrigger: 3jQuery111304105261403454039: truenamespace: ""namespace_re: nulloriginalEvent: jQuery.Event {type: "add", delegatedEvent: j…y.Event, timeStamp: 1561917127348, jQuery111304105261403454039: true}result: undefinedtarget: input#fileuploadtimeStamp: 1561917127348type: "fileuploadadd"__proto__: Object

     trigger后面的代码是

    return !( $.isFunction( callback ) &&
    callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
    event.isDefaultPrevented() );

    callback对应下面的add

    // 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 () {        //这里的process是在_addConvenienceMethods里面定义的
                        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);
                                }
                            });
                        }
                    });
                },

    jquery.fileupload-ui.js里面的

     _renderUpload: function (files) {
                return this._renderTemplate(
                    this.options.uploadTemplate,  //自己做测试的,这边是null
                    files
                );
            },
    _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();
            },
    _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;
            },
     data.process = function (resolveFunc, rejectFunc) {
                    if (resolveFunc || rejectFunc) {
                        data._processQueue = this._processQueue =
                            (this._processQueue || getPromise([this])).then(
                                function () {
                                    if (data.errorThrown) {
                                        return $.Deferred()
                                            .rejectWith(that, [data]).promise();
                                    }
                                    return getPromise(arguments);
                                }
                            ).then(resolveFunc, rejectFunc);
                    }
                    return this._processQueue || getPromise([this]);
                };

    然后跳转jquery.fileupload-ui.js里面

     // Processes the files given as files property of the data parameter,
            // returns a Promise object that allows to bind callbacks:
            process: function (data) {
                var that = this,
                    options = $.extend({}, this.options, data);
                if (options.processQueue && options.processQueue.length) {
                    this._transformProcessQueue(options);
                    if (this._processing === 0) {
                        this._trigger('processstart');
                    }
                    $.each(data.files, function (index) {
                        var opts = index ? $.extend({}, options) : options,
                            func = function () {
                                if (data.errorThrown) {
                                    return $.Deferred()
                                            .rejectWith(that, [data]).promise();
                                }
                                return that._processFile(opts, data);
                            };
                        opts.index = index;
                        that._processing += 1;
                        that._processingQueue = that._processingQueue.then(func, func)
                            .always(function () {
                                that._processing -= 1;
                                if (that._processing === 0) {
                                    that._trigger('processstop');
                                }
                            });
                    });
                }
                return this._processingQueue;
            },
    // Replaces the settings of each processQueue item that
            // are strings starting with an "@", using the remaining
            // substring as key for the option map,
            // e.g. "@autoUpload" is replaced with options.autoUpload:
            _transformProcessQueue: function (options) {
                var processQueue = [];
                $.each(options.processQueue, function () {
                    var settings = {},
                        action = this.action,
                        prefix = this.prefix === true ? action : this.prefix;
                    $.each(this, function (key, value) {
                        if ($.type(value) === 'string' &&
                                value.charAt(0) === '@') {
                            settings[key] = options[
                                value.slice(1) || (prefix ? prefix +
                                    key.charAt(0).toUpperCase() + key.slice(1) : key)
                            ];
                        } else {
                            settings[key] = value;
                        }
    
                    });
                    processQueue.push(settings);
                });
                options.processQueue = processQueue;
            },
     processstart: function (e) {
                    if (e.isDefaultPrevented()) {
                        return false;
                    }
                    $(this).addClass('fileupload-processing');
                },

    然后是jquery.fileupload-process.js里面的

    _processFile: function (data, originalData) {
                var that = this,
                    dfd = $.Deferred().resolveWith(that, [data]),
                    chain = dfd.promise();
                this._trigger('process', null, data);
                $.each(data.processQueue, function (i, settings) {
                    var func = function (data) {
                        if (originalData.errorThrown) {
                            return $.Deferred()
                                    .rejectWith(that, [originalData]).promise();
                        }
                        return that.processActions[settings.action].call(
                            that,
                            data,
                            settings
                        );
                    };
                    chain = chain.then(func, settings.always && func);
                });
                chain
                    .done(function () {
                        that._trigger('processdone', null, data);
                        that._trigger('processalways', null, data);
                    })
                    .fail(function () {
                        that._trigger('processfail', null, data);
                        that._trigger('processalways', null, data);
                    });
                return chain;
            },
     // Processes the files given as files property of the data parameter,
            // returns a Promise object that allows to bind callbacks:
            process: function (data) {
                var that = this,
                    options = $.extend({}, this.options, data);
                if (options.processQueue && options.processQueue.length) {
                    this._transformProcessQueue(options);
                    if (this._processing === 0) {
                        this._trigger('processstart');
                    }
                    $.each(data.files, function (index) {
                        var opts = index ? $.extend({}, options) : options,
                            func = function () {
                                if (data.errorThrown) {
                                    return $.Deferred()
                                            .rejectWith(that, [data]).promise();
                                }
                                return that._processFile(opts, data);
                            };
                        opts.index = index;
                        that._processing += 1;
                        that._processingQueue = that._processingQueue.then(func, func)
                            .always(function () {
                                that._processing -= 1;
                                if (that._processing === 0) {
                                    that._trigger('processstop');
                                }
                            });
                    });
                }
                return this._processingQueue;
            },

    结论

    绑定事件的时候依赖于this.options.filesContainer,这玩意不存在于jquery.fileupload.js里面

     _initEventHandlers: function () {
                this._super();
    
                var handlers = {};
                handlers[this.options.uploadImageEditorPreviewSelector] = this._previewHandler.bind(this);
                console.log(`filesContainer = ${this.options.filesContainer}`);
                this._on(this.options.filesContainer, handlers);
            },

    而filesContainer在jquery.fileupload-ui.js中

     // 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,
    
    _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);
                }
            },

    因为basic.html没有引用jquery.fileupload-ui.js,所以导致事件绑定失败。

     顺便打印一下this.element

    console.log(`filesContainer = ${this.options.filesContainer}`);
    console.log(this.element);

     自己手动复制函数,然后在_initEventHandlers里面调用

      _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);
                }
            },
            _initEventHandlers: function () {
                this._super();
                this._initFilesContainer();
                var handlers = {};
                handlers[this.options.uploadImageEditorPreviewSelector] = this._previewHandler.bind(this);
                this._on(this.options.filesContainer, handlers);
            },

    页面加载后,进行查询

    $('#fileupload').fileupload('option', 'filesContainer')

    在还有jquery.fileupload-ui.js里面还有关于uploadTemplateID的设置

    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',
  • 相关阅读:
    Vue_(组件通讯)父子组件简单关系
    JavaWeb_(Struts2框架)Struts创建Action的三种方式
    JavaWeb_(Struts2框架)Servlet与Struts区别
    Vue_(组件通讯)动态组件结合keep-alive
    Vue_(组件通讯)动态组件
    Vue_(组件通讯)组件
    JavaWeb_(Struts2框架)使用Struts框架实现用户的登陆
    JavaWeb_(Struts2框架)使用Servlet实现用户的登陆
    原生Js_实现广告弹窗
    原生Js_简易图片轮播模板
  • 原文地址:https://www.cnblogs.com/chucklu/p/11111987.html
Copyright © 2011-2022 走看看