elementui+vue cropper 裁剪图片封装

公共裁剪页面

<style>
    .el-dialog__header {
        padding: 24px 0 11px 28px;
    }

    .el-dialog__title {
        color: #333333;
    }

    .el-dialog__body {
        padding: 0 28px;
    }

    .el-dialog__footer {
        padding: 20px 28px;
    }

    .avatar {
        display: flex;
    }

    .avatar-left {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 400px;
        height: 400px;
        background-color: #F0F2F5;
        margin-right: 10px;
        border-radius: 4px;
    }

    .avatar-left-crop {
        width: 400px;
        height: 400px;
        position: relative;
    }

    .crop-box {
        width: 100%;
        height: 100%;
        border-radius: 4px;
        overflow: hidden
    }

    .avatar-left-p {
        text-align: center;
        width: 100%;
        position: absolute;
        bottom: 20px;
        color: #ffffff;
        font-size: 14px;
    }

    .avatar-right {
        width: 150px;
        height: 400px;
        background-color: #F0F2F5;
        border-radius: 4px;
        padding: 16px 0;
        box-sizing: border-box;
    }

    .avatar-right-div {
        border: 3px solid #ffffff;
        border-radius: 50%;
    }

    .avatar-right-previews {
        width: 200px;
        height: 200px;
        overflow: hidden;
        border-radius: 50%;
    }

    .avatar-right-text {
        text-align: center;
        margin-top: 50px;
        font-size: 14px;
    }

    span {
        color: #666666;
    }

    .cropper-view-box,
    .cropper-face,
    .preview {
        border-radius: 50%;
    }
</style>
<script src="~/Scripts/jquery-3.4.1.min.js"></script>
<script src="~/Scripts/vue.min.js"></script>
<script src="~/Scripts/ElementUI/index.js"></script>
<script src="~/Scripts/ElementUI/locale/en.js"></script>
<script src="~/Scripts/cropper/cropper.min.js"></script>
<link href="~/Scripts/cropper/cropper.min.css" rel="stylesheet" />
<div id="app">
    <div style="display: flex" class="avatar">
        <div class="avatar-left">
            <div v-if="!optionsPhoto.img">
                @*<el-upload ref="upload"
                               action=""
                               style="text-align: center;margin-bottom: 24px"
                               :on-change="uploads"
                               accept="image/png, image/jpeg, image/jpg"
                               :show-file-list="false"
                               :auto-upload="false">
                        <el-button slot="trigger" size="small" type="primary" ref="uploadBtn">选择图片</el-button>
                    </el-upload>*@
                <input type="file" id="doc" accept="image/*" v-on:change="CropperSetImagePreview1()" />
                <div>支持jpg、png格式的图片,大小不超过3M</div>
            </div>
            <div v-show="optionsPhoto.img" class="avatar-left-crop">
                <div class="col col-6" id="localImag">
                    <img id="image" src="../docs/images/picture.jpg" alt="Picture">
                </div>
                <p class="avatar-left-p">
                    鼠标滚轮缩放控制图片显示大小,鼠标拖拽调整显示位置
                </p>
            </div>
        </div>
        <div class="avatar-right">
            <div class="avatar-right-div" v-for="item in previewsDiv" :style="item.style">
                <div v-show="optionsPhoto.img" :class="previews.div" class="avatar-right-previews" :style="item.zoomStyle">
                    <div class="preview"></div>
                </div>
            </div>
            <div class="avatar-right-text">
                <el-button v-if="optionsPhoto.img" type="text" v-on:click="uploadPreviews">重新上传</el-button>
                <span v-else>预览</span>
            </div>
        </div>
    </div>
    <span slot="footer" class="dialog-footer">
        <el-button v-on:click="CropDialogVisible=false">取 消</el-button>
        <el-button type="primary" v-on:click="getCrop">确 定</el-button>
    </span>
</div>

<script>
    function each(arr, callback) {
        var length = arr.length;
        var i;

        for (i = 0; i < length; i++) {
            callback.call(arr, arr[i], i, arr);
        }

        return arr;
    }
    var cropper;
    $(function () {
        var layerIndex;
        ELEMENT.locale(ELEMENT.lang.en);
        var vue = new Vue({
            el: '#app',
            data: {
                optionsPhoto: { img: false },
                CropDialogVisible: false,
                //实时预览图数据
                previews: {},
                previewsDiv: [
                    //108px 预览样式
                    {
                        style: {
                             '108px',
                            height: '108px',
                            margin: '0 auto'
                        },
                        zoomStyle: {
                            zoom: 0.54
                        }
                    },
                    //68px 预览样式
                    {
                        style: {
                             '68px',
                            height: '68px',
                            margin: '27px auto'
                        },
                        zoomStyle: {
                            zoom: 0.34
                        }
                    },
                    //48px 预览样式
                    {
                        style: {
                             '48px',
                            height: '48px',
                            margin: '0 auto'
                        },
                        zoomStyle: {
                            zoom: 0.24
                        }
                    }
                ]
            },
            methods: {
                uploadPreviews: function () { },
                uploads(file) {
                    const isIMAGE = file.raw.type === 'image/jpeg' || file.raw.type === 'image/png';
                    const isLt3M = file.raw.size / 1024 / 1024 < 3;
                    if (!isIMAGE) {
                        this.$message({
                            showClose: true,
                            message: '请选择 jpg、png 格式的图片!',
                            type: 'error',  //提示类型
                        });
                        return false;
                    }
                    if (!isLt3M) {
                        this.$message({
                            showClose: true,
                            message: '上传图片大小不能超过 3MB',
                            type: 'error',  //提示类型
                        });
                        return false;
                    }
                    let reader = new FileReader();
                    reader.readAsDataURL(file.raw);
                    reader.onload = e => {
                        this.optionsPhoto.img = e.target.result //base64
                    }
                },
                CropperSetImagePreview: function () {
                    this.CropDialogVisible = true;
                },
                CropperSetImagePreview1: function () {
                    var docObj = document.getElementById("doc");
                    console.log(docObj.files)
                    var imgObjPreview = document.getElementById("image");
                    if (docObj.files && docObj.files[0]) {
                        //火狐下,直接设img属性
                        imgObjPreview.style.display = 'block';
                        imgObjPreview.style.maxWidth = '960px';
                        imgObjPreview.style.height = '400px';
                        //imgObjPreview.src = docObj.files[0].getAsDataURL();
                        // 取绝对路径的getAsDataURL

                        //火狐7以上版本不能用上面的getAsDataURL()方式获取,需要一下方式
                        imgObjPreview.src = window.URL.createObjectURL(docObj.files[0]);
                    } else {
                        //IE下,使用滤镜
                        docObj.select();
                        var imgSrc = document.selection.createRange().text;
                        var localImagId = document.getElementById("localImag");
                        //必须设置初始大小
                        localImagId.style.maxWidth = "960px";
                        localImagId.style.height = 'auto';
                        //图片异常的捕捉,防止用户修改后缀来伪造图片
                        try {
                            localImagId.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale)";
                            localImagId.filters.item("DXImageTransform.Microsoft.AlphaImageLoader").src = imgSrc;
                        } catch (e) {
                            alert("您上传的图片格式不正确,请重新选择!");
                            return false;
                        }
                        imgObjPreview.style.display = 'none';
                        document.selection.empty();
                    }

                    this.changeFile();
                    this.previews.url = window.URL.createObjectURL(docObj.files[0]);
                    this.optionsPhoto.img = true;
                },

                changeFile: function () {
                    var image = document.querySelector('#image');
                    var previews = document.querySelectorAll('.preview');
                    cropper = new Cropper(image, {
                        aspectRatio: 1,
                        toggleDragModeOnDblclick: false,
                        cropBoxResizable: true,
                        cropBoxMovable: true,
                        highlight: false,
                        center: false,
                        guides: false,
                        restore: false,
                        autoCropArea: 0.65,
                        dragMode: 'move',
                        // movable:false,
                        ready: function () {
                            var clone = this.cloneNode();
                            croppable = true;
                            clone.className = ''
                            clone.style.cssText = (
                                'display: block;' +
                                ' 100%;' +
                                'min- 0;' +
                                'min-height: 0;' +
                                'max- none;' +
                                'max-height: none;'
                            );
                            each(previews, function (elem) {
                                elem.appendChild(clone.cloneNode());
                            });
                        },
                        // 类型: Function
                        // 默认: null“ cropper” 事件的捷径。
                        crop: function (e) {
                            var data = e.detail;
                            var cropper = this.cropper;
                            var imageData = cropper.getImageData(); //输出图像位置,大小等相关数据。
                            var previewAspectRatio = data.width / data.height;

                            each(previews, function (elem) {
                                var previewImage = elem.getElementsByTagName('img').item(0);
                                var previewWidth = elem.offsetWidth;
                                var previewHeight = previewWidth / previewAspectRatio;
                                var imageScaledRatio = data.width / previewWidth;

                                elem.style.height = previewHeight + 'px';
                                previewImage.style.width = imageData.naturalWidth / imageScaledRatio + 'px';
                                previewImage.style.height = imageData.naturalHeight / imageScaledRatio + 'px';
                                previewImage.style.marginLeft = -data.x / imageScaledRatio + 'px';
                                previewImage.style.marginTop = -data.y / imageScaledRatio + 'px';
                            });
                        },

                    });

                },
                getRoundedCanvas: function (sourceCanvas) {
                    var canvas = document.createElement('canvas');
                    var context = canvas.getContext('2d');
                    var width = sourceCanvas.width;
                    var height = sourceCanvas.height;
                    canvas.width = width;
                    canvas.height = height;
                    context.imageSmoothingEnabled = true;
                    context.drawImage(sourceCanvas, 0, 0, width, height);
                    context.globalCompositeOperation = 'destination-in';
                    context.beginPath();
                    context.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI, true);
                    context.fill();
                    return canvas;
                },
                getCrop: function () {
                    var croppedCanvas;
                    var roundedCanvas;
                    var roundedImage;

                    if (!croppable) {
                        return;
                    }
                    // Crop
                    croppedCanvas = cropper.getCroppedCanvas();
                    // Round
                    roundedCanvas = this.getRoundedCanvas(croppedCanvas);
                    // Show
                    roundedImage = document.createElement('img');
                    roundedImage.src = roundedCanvas.toDataURL()
                    blob = this.dataURLtoBlob(roundedCanvas.toDataURL());


                  //  this.UserInfo.UserPhoto = roundedImage.src;
                    parent.vue.CloseCropPicture(roundedImage.src);
                },
                dataURLtoBlob: function (dataurl) {
                    var arr = dataurl.split(','),
                        mime = arr[0].match(/:(.*?);/)[1],
                        bstr = atob(arr[1]),
                        n = bstr.length,
                        u8arr = new Uint8Array(n);
                    while (n--) {
                        u8arr[n] = bstr.charCodeAt(n);
                    }
                    return new Blob([u8arr], {
                        type: mime
                    });
                },
            },
            mounted: function () {
            
            }
        });

    });

</script>

父页面

            <div class="PP--main-left">

                <template v-if="IsPreview">
                    <img id="image" style="height:214px;214px" :src="UserInfo.UserPhoto" :key="UserInfo.UserPhoto" alt="Picture" />
                </template>
                <template v-else>
                    <div class="poto" style="cursor:pointer" v-on:click="CropperSetImagePreview()">
                        <template v-if="UserInfo.UserPhoto==null||UserInfo.UserPhoto==''">
                            <i class="pwc-icon pwc-upload-outline"></i>
                            <span>Upload image</span>
                        </template>
                        <template v-else>
                            <img style="214px;height:214px;" :src="UserInfo.UserPhoto" :key="UserInfo.UserPhoto"></img>
                        </template>
                    </div>
                </template>
                <div style="display:none">

                    <input type="file" id="file" accept="image/*" v-on:change="UpLoadFile(1)" />
                </div>
            </div>
 

<div>
        <el-dialog :visible.sync="dialogVisibleCop"
                   width="30%">
            <iframe :src="frameUrlCrop" frameborder="0" width="100%" height="527px"></iframe>
            <span slot="footer" class="dialog-footer">
            </span>
        </el-dialog>
    </div>

  CropperSetImagePreview: function () {
                    this.dialogVisibleCop = true;
                    this.frameUrlCrop=rootUrl + "Common/CropPicture"
                },
                CloseCropPicture: function (base64Photo) {
                    this.UserInfo.UserPhoto = base64Photo;
                    this.dialogVisibleCop = false;
                },

参考文档

https://blog.csdn.net/XHL1314mmq/article/details/105815966

https://blog.csdn.net/qq_41389920/article/details/87967539

原文地址:https://www.cnblogs.com/happygx/p/14626704.html