0

如何在不使用 Ajax 的情况下使用 Cropper.js 编辑图像后上传图像?

HTML

<div class="block-content" id=profile-image>
    <div class="row pb-3">
        <div class="col-12">
            <label>Profile Image</label>
            <div class="options-container">
                <img class="img-fluid options-item image-edit" id="image-place"
                     src="{{ $user->avatar ? asset(App\User::PROFILE_IMAGE_PATH . $user->avatar) : 'media/avatars/avatar-male.jpg' }}"
                     alt="Profile Image" style="max-width: 100%">
            </div>
        </div>
    </div>
    <div class="btn-group">
        <button type="button" class="btn btn-primary" data-method="reset" title="Reset">
            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title="">
                <span class="fa fa-sync-alt"></span>
            </span>
        </button>
        <label class="btn btn-primary btn-upload" for="fileEdit" title="Upload image file">
            <input type="file" class="sr-only" id="fileEdit" name="file" accept=".jpg,.jpeg,.png,.gif,.bmp,.tiff">
            <input type="hidden" class="sr-only" id="hiddenBlob" name="hiddenBlob">
            <span class="docs-tooltip" data-toggle="tooltip" data-animation="false" title=""
                  data-original-title="Import image with Blob URLs">
                <span class="fa fa-upload"></span>
            </span>
        </label>
    </div>
    <div class="row">
        <div class="col-12">
            <div class="form-group text-center">
                <button type="submit" class="btn btn-block btn-hero-lg btn-hero-primary">
                    <i class="si si-reload mr-1"></i> Update Profile
                </button>
            </div>
        </div>
    </div>
</div>

JS

$(function () {
    'use strict';

    let console     = window.console || { log: function () { } }
    let URL         = window.URL || window.webkitURL;
    let $image      = $('.image-edit');
    let $dataX      = $('#dataX');
    let $dataY      = $('#dataY');
    let $dataHeight = $('#dataHeight');
    let $dataWidth  = $('#dataWidth');
    let $dataRotate = $('#dataRotate');
    let $dataScaleX = $('#dataScaleX');
    let $dataScaleY = $('#dataScaleY');
    let options     = {
        aspectRatio: 16 / 9,
        preview: '.img-preview',
        crop: function (e) {
            $dataX.val(Math.round(e.detail.x));
            $dataY.val(Math.round(e.detail.y));
            $dataHeight.val(Math.round(e.detail.height));
            $dataWidth.val(Math.round(e.detail.width));
            $dataRotate.val(e.detail.rotate);
            $dataScaleX.val(e.detail.scaleX);
            $dataScaleY.val(e.detail.scaleY);
        }
    }

    let originalImageURL  = $image.attr('src');
    let uploadedImageName = 'cropped.jpg';
    let uploadedImageType = 'image/jpeg';
    let uploadedImageURL;

    let cropper = new window.Cropper(document.getElementById('image-place'), options)

    // Cropper
    $image.on({
        ready: function (e) {
            // console.log(e.type);
        },
        cropstart: function (e) {
            // console.log(e.type, e.detail.action);
        },
        cropmove: function (e) {
            // console.log(e.type, e.detail.action);
        },
        cropend: function (e) {
            // console.log(e.type, e.detail.action);
        },
        crop: function (e) {



            cropper.getCroppedCanvas().toBlob(function(blob){
                console.log(blob.text())
            })

        },
        zoom: function (e) {
            // console.log(e.type, e.detail.ratio);
        }
    }).cropper(options);

    // Buttons
    if (!$.isFunction(document.createElement('canvas').getContext)) {
        $('button[data-method="getCroppedCanvas"]').prop('disabled', true);
    }

    if (typeof document.createElement('cropper').style.transition === 'undefined') {
        $('button[data-method="rotate"]').prop('disabled', true);
        $('button[data-method="scale"]').prop('disabled', true);
    }

    // Options
    $('.docs-toggles').on('change', 'input', function () {
        let $this = $(this);
        let name = $this.attr('name');
        let type = $this.prop('type');
        let cropBoxData;
        let canvasData;

        if (!$image.data('cropper')) {
            return;
        }

        if (type === 'checkbox') {
            options[name] = $this.prop('checked');
            cropBoxData = $image.cropper('getCropBoxData');
            canvasData = $image.cropper('getCanvasData');

            options.ready = function () {
                $image.cropper('setCropBoxData', cropBoxData);
                $image.cropper('setCanvasData', canvasData);
            }
        } else if (type === 'radio') {
            options[name] = $this.val();
        }

        $image.cropper('destroy').cropper(options);

        $image.cropper('getCroppedCanvas').toBlob(function (blob) {
            console.log(blob);

        })
    });

    // Methods
    $('#profile-image').on('click', '[data-method]', function () {
        let $this = $(this);
        let data = $this.data();
        let cropper = $image.data('cropper');
        let cropped;
        let $target;
        let result;

        if ($this.prop('disabled') || $this.hasClass('disabled')) {
            return;
        }

        if (cropper && data.method) {
            data = $.extend({}, data); // Clone a new one

            if (typeof data.target !== 'undefined') {
                $target = $(data.target);

                if (typeof data.option === 'undefined') {
                    try {
                        data.option = JSON.parse($target.val());
                    } catch (e) {
                        console.log(e.message);
                    }
                }
            }

            cropped = cropper.cropped;

            switch (data.method) {
                case 'rotate':
                    if (cropped && options.viewMode > 0) {
                        $image.cropper('clear');
                    }

                    break;

                case 'getCroppedCanvas':
                    if (uploadedImageType === 'image/jpeg') {
                        if (!data.option) {
                            data.option = {}
                        }

                        data.option.fillColor = '#fff';
                    }

                    break;
            }

            result = $image.cropper(data.method, data.option, data.secondOption);

            switch (data.method) {
                case 'rotate':
                    if (cropped && options.viewMode > 0) {
                        $image.cropper('crop');
                    }

                    break;

                case 'scaleX':
                case 'scaleY':
                    $(this).data('option', -data.option);
                    break;

                case 'getCroppedCanvas':
                    if (result) {
                        Swal.fire({
                            title: 'Info!',
                            html: result,
                            type: 'success',
                        })
                    }

                    break;

                case 'destroy':
                    if (uploadedImageURL) {
                        URL.revokeObjectURL(uploadedImageURL);
                        uploadedImageURL = '';
                        $image.attr('src', originalImageURL);
                    }

                    break;
            }

            if ($.isPlainObject(result) && $target) {
                try {
                    $target.val(JSON.stringify(result));
                } catch (e) {
                    console.log(e.message);
                }
            }
        }
    });

    // Keyboard
    $(document.body).on('keydown', function (e) {
        if (e.target !== this || !$image.data('cropper') || this.scrollTop > 300) {
            return;
        }

        switch (e.which) {
            case 37:
                e.preventDefault();
                $image.cropper('move', -1, 0);
                break;

            case 38:
                e.preventDefault();
                $image.cropper('move', 0, -1);
                break;

            case 39:
                e.preventDefault();
                $image.cropper('move', 1, 0);
                break;

            case 40:
                e.preventDefault();
                $image.cropper('move', 0, 1);
                break;
        }
    });

    // Import image
    let $inputImage = $('#fileEdit');

    if (URL) {
        $inputImage.change(function () {
            let files = this.files;
            let file;

            if (!$image.data('cropper')) {
                return;
            }

            if (files && files.length) {
                file = files[0];


                if (/^image\/\w+$/.test(file.type)) {
                    uploadedImageName = file.name;
                    uploadedImageType = file.type;

                    if (uploadedImageURL) {
                        URL.revokeObjectURL(uploadedImageURL);
                    }

                    uploadedImageURL = URL.createObjectURL(file);
                    $image.cropper('destroy').attr('src', uploadedImageURL).cropper(options);

                } else {
                    window.alert('Please choose an image file.');
                }
            }
        });
    } else {
        $inputImage.prop('disabled', true).parent().addClass('disabled');
    }
});
4

1 回答 1

1

由于设置文件输入元素的值是“不可能的”,因此您只能使用XMLHttpRequestfetch也称为 Ajax 上传新创建的文件/图像。

您可以将文件编码为 base64 数据,然后将其存储在隐藏的输入元素中,但是对于大文件,大量的 base64 编码数据会导致浏览器内存不足。它还可以触发服务器上的自动安全措施。

<input type="file">
<input type="hidden">

<script>
document.querySelector('input[type="file"]').onchange = e => {
    const reader = new FileReader();
    reader.onloadend = () => {
        document.querySelector('input[type="hidden"]').value = reader.result;
    };
    reader.readAsDataURL(e.target.files[0]);
};
</script>

幸运的是,在最新版本的 Firefox 和 Chrome 上,可以使用该DataTransfer对象来更新文件输入元素files属性,这将允许同步上传。不幸的是,在撰写本文时,仅这两种浏览器支持此功能。

<input type="file">

<script>
// Create a DataTransfer instance and add a newly created file
const dataTransfer = new DataTransfer();
dataTransfer.items.add(new File(['hello world'], 'This_Works.txt'))

// Assign the DataTransfer files list to the file input
document.querySelector('input').files = dataTransfer.files;
</script>

更多关于编辑和上传文件数据的信息可以在这里找到: https ://pqina.nl/blog/the-trouble-with-editing-and-uploading-files-in-the-browser/

于 2019-12-16T06:53:47.067 回答