如何在异步环境中让Dropzone和Cropper.js很好地一起玩?

时间:2018-06-19 16:37:35

标签: javascript dropzone cropperjs

我已使用https://gist.github.com/maria-p/8633b51f629ea8dbd27e处的代码作为在异步环境中将dropzone与cropperjs集成的基础,因此用户需要能够打开多个CRUD模式并上传/裁剪图像而不必刷新网页。

经过几天的研究,实验和撕下我剩下的小毛发,我有了一个脚本,该脚本现在对于上载和裁剪的第一张图片可以100%完美地工作,但是在随后的上载之前存在一些问题任何页面刷新。后续的上载导致控制台错误“ 无法读取null的属性'insertBefore'”,该错误与以下cropperjs代码片段有关:

key: "build",
value: function() {
    if (this.sized && !this.ready) {
        var A = this.element
          , t = this.options
          , e = this.image
          , s = A.parentNode
          , n = document.createElement("div");
        n.innerHTML = '<div class="cropper-container" ... >';
        var r = n.querySelector("." + D + "-container")
        //[snip]
        s.insertBefore(r, A.nextSibling) // <<<<<<<<<<<< this line

...换句话说,即使元素周围的代码似乎工作正常,也无法找到该元素的父节点,因为出现了裁剪器工具。仅控制台错误并没有什么大不了的,但它可以明确指出其他问题,因为图像旋转和翻转按钮的行为异常(在后续上传中),除非同一图像连续连续上传三次。我还注意到,出于某种原因,我从dropzone得到了两个“成功”响应,但仅当上传后续图像时才如此。所有上传均成功,只是操作按钮在第一个操作后不起作用。

有人可以帮助我解决此问题吗?我认为很重要的代码如下:

var reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = function() {

    cropperModal.modal('show');

    cropperModal.on('shown.bs.modal', function() {

        var image = $('<img/>');
        cropperModal.find('.image-container').html(image);
        image.attr('src', reader.result).attr('id', 'cropper-image');

        cropper = new Cropper(document.getElementById('cropper-image'), {
            autoCropArea: 1,
            aspectRatio: imgRatio,
            ready: function () {
                myDropzone.removeFile(file);
            }
        });
    });
};

...但是为了防万一,这是我完整的脚本(基于this):

    // configure the upload routine
    var imgRatio = 1.618; // aspect ratio of the saved images
    var imgWidth = 600; // fixed width of the saved images (pix)
    var imgQuality = 0.9; // quality of the saved image (e.g. 0.9)
    var maxUpload = 5; // maximum uploaded file size (MB)

    // transform cropper dataURI output to a Blob which Dropzone accepts
    function dataURItoBlob(dataURI) {
        var byteString = atob(dataURI.split(',')[1]);
        var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        return new Blob([ab], { type: 'image/jpeg' });
    }

    // initialize dropzone
    Dropzone.autoDiscover = false;
    var myDropzone = new Dropzone('#dropzone1', {
        url: '/foo/bar/',
        autoProcessQueue: false,
        uploadMultiple: false,
        maxFilesize: maxUpload,
        dictDefaultMessage: '!{$labels["pic_upload"]}',
        acceptedFiles: '.png, .jpg, .jpeg, .gif',
        addRemoveLinks: true,
        init: function() {
            myDropzone = this;
            this.on("success", function(file, responseText) {
                console.log('Success responseText = ' + responseText);
                if (responseText == 'success') {
                    // show success dialogue
                    swal({ title: '#{$labels["upload_success"]}', timer: 3000, icon: 'success', buttons: false });
                } else {
                    // show error dialogue
                    swal({ title: '!{$labels["upload_error"]}', text: '"' + responseText + '"', icon: 'error' });
                }
            });
            this.on("error", function (file, errorMessage) {
                console.log('Error file = ' + JSON.stringify(file, null, 4));
                console.log('Error errorMessage = ' + errorMessage);
                swal({ title: '!{$labels["upload_error"]}', text: '"' + errorMessage + '"', icon: 'error' });
            });
        }
    });

    // listen to thumbnail event
    myDropzone.on('thumbnail', function (file) {

        // ignore files already cropped to prevent infinite loop
        if (file.cropped) { 
            return; 
        }

        // add the original filename to the dropzone URL (for recording in the file upload log)
        myDropzone.options.url = '/foo/bar/' + encodeURIComponent(file.name);

        // check the file extension type
        var re = /(?:\.([^.]+))?$/;
        var ext = re.exec(file.name)[1];
        ext = ext.toUpperCase();
        if (ext != "JPG" && ext != "JPEG" && ext != "GIF" && ext != "PNG") {
            swal({ title: '!{$labels["upload_wrongext"]}', icon: 'error' });
            return;
        }

        // prevent the upload if the file is too small
        if (file.width < 400) {
            swal({ title: '!{$labels["upload_toosmall"]}', icon: 'error' });
            return;
        }

        // check the filesize does not exceed the maximum allowed
        if (file.size > (maxUpload*1000000)) {
            swal({ title: '!{$labels["upload_toolarge"]}', icon: 'error' });
            return;
        }

        // target all required modal elements
        var cropperModal = $('#cropper-modal');
        var rotateLButton = cropperModal.find('.rotate-left');
        var rotateRButton = cropperModal.find('.rotate-right');
        var scaleXButton = cropperModal.find('.scale-x');
        var scaleYButton = cropperModal.find('.scale-y');
        var resetButton = cropperModal.find('.reset');
        var uploadButton = cropperModal.find('.crop-upload');

        // initialize FileReader and read uploaded file
        var reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onloadend = function() {

            // open the bootstrap modal
            cropperModal.modal('show');

            // initialize cropper.js after the modal has loaded
            cropperModal.on('shown.bs.modal', function() {

                // load the submitted image ready for cropping
                var image = $('<img/>');
                cropperModal.find('.image-container').html(image);
                image.attr('src', reader.result).attr('id', 'cropper-image');

                // initialize cropper.js (must use native js targeting)
                cropper = new Cropper(document.getElementById('cropper-image'), {
                    autoCropArea: 1,
                    aspectRatio: imgRatio,
                    ready: function () {
                        // remove un-cropped thumbnail from dropzone
                        myDropzone.removeFile(file);
                    }
                });
            });
        };

        // carry out image manipulation actions
        // putting these functions inside the 'ready' makes no difference to the error issue
        rotateLButton.on('click', function() { 
            cropper.rotate(90);
        });
        rotateRButton.on('click', function() { 
            cropper.rotate(-90);
        });
        scaleXButton.on('click', function() {
            var $this = $(this);
            cropper.scaleX($this.data('value'));
            $this.data('value', -$this.data('value'));
        });
        scaleYButton.on('click', function() {
            var $this = $(this);
            cropper.scaleY($this.data('value'));
            $this.data('value', -$this.data('value'));
        });
        resetButton.on('click', function() { 
            cropper.reset();
        });
        uploadButton.on('click', function() {
            // get cropped image data
            var blob = cropper.getCroppedCanvas( { width: imgWidth } ).toDataURL('image/jpeg', imgQuality);
            // transform it to Blob object
            var newFile = dataURItoBlob(blob);
            // set 'cropped to true' so that we don't hit that listener again
            newFile.cropped = true;
            // assign resource ID as filename
            newFile.name = 'foobar.jpg';
            // add cropped file to dropzone
            myDropzone.addFile(newFile);
            // upload cropped file with dropzone
            myDropzone.processQueue();
            // close the cropper modal
            cropperModal.modal('hide');
        });

        // remove thumbnail after upload to server
        myDropzone.on('complete', function(file) {
            myDropzone.removeFile(file);
        });
    });

依赖关系:cropperjs 1.4.0; Dropzone 5.4.0; jQuery 3.3.1;铬67.0.3396.87

0 个答案:

没有答案