美文网首页Vue
vue中使用cropperjs实现上传头像并裁剪

vue中使用cropperjs实现上传头像并裁剪

作者: 陶菇凉 | 来源:发表于2021-03-26 14:40 被阅读0次

    效果图:


    image.png

    1.首先安装 npm install cropperjs

    2.封装组件

    <template>
        <div class="Upload">
            <el-dialog v-el-drag-dialog title="更换头像" :visible.sync="dialogVisible" :append-to-body="false">
                <el-row :gutter="10">
                    <el-col :span="14">
                        <div class="container">
                            <div>
                                <img id="image" :src="url" alt="Picture" />
                            </div>
                            <div style="text-align: center;">
                                <el-button @click="handleAdd" style="margin:10px 0 auto;">上传图片</el-button>
                                <form enctype="multipart/form-data" class="handle_add" name="fileinfo" @click="handleAdd">
                                    <input type="file" id="change" ref="inputFile" :accept="accept" @change="change">
                                    <label for="change"></label>
                                </form>
                            </div>
                        </div>
                    </el-col>
                    <el-col :span="10">
                        <div class="yulan">
                            <div>
                                预览
                            </div>
                            <div style="text-align: center;" class="small">
                            </div>
                        </div>
                    </el-col>
                </el-row>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="dialogClose">取 消</el-button>
                    <el-button type="primary" @click="crop">确 定</el-button>
                </div>
            </el-dialog>
        </div>
    </template>
    
    <script>
    import Cropper from 'cropperjs'
    export default {
        props: {
            accept: {
                type: String,
                default: 'image/jpeg,image/jpg,image/png,,image/gif'
            },
            fileSize: {
                type: Number,
                default: 1
            }
        },
        data() {
            return {
                headerImage: '',
                picValue: '',
                cropper: '',
                croppable: false,
                url: require("../../../public/img/headmr.jpg"),
                dialogVisible: false,
                fileData: "",
            }
        },
        methods: {
            dialogChange(data) {
                this.dialogVisible = true;
                //      // 初始化这个裁剪框
                const self = this
                this.$nextTick(function() {
                    //不能多事初始化裁剪框
                    if(this.cropper) {
                        return false
                    }
                    const image = document.getElementById('image')
                    this.cropper = new Cropper(image, {
                        aspectRatio: 1,
                        viewMode: 1,
                        background: false,
                        zoomable: false,
                        preview: ".small",
                        ready: function() {
                            self.croppable = true
                        },
                        crop: function() {
                            //              self.crop()
                        }
                    })
                })
            },
            dialogClose() {
                this.dialogVisible = false
            },
            limitUpload(file) {
                if(file.size > this.fileSize * 1024 * 1024) {
                    this.$message({
                        type: 'error',
                        message: `图片大小不允许超过${this.fileSize}M`
                    })
                    return false
                }
            },
            getObjectURL(file) {
                // this.limitUpload(file)
                let url = null
                if(window.createObjectURL !== undefined) { // basic
                    url = window.createObjectURL(file)
                } else if(window.URL !== undefined) { // mozilla(firefox)
                    url = window.URL.createObjectURL(file)
                } else if(window.webkitURL !== undefined) { // webkit or chrome
                    url = window.webkitURL.createObjectURL(file)
                }
                return url
            },
            change(e) {
                const files = e.target.files || e.dataTransfer.files
                if(!files.length) return
                this.picValue = files[0]
                this.url = this.getObjectURL(this.picValue)
                if(this.cropper) {
                    this.cropper.replace(this.url)
                }
                event.target.value = ''
            },
            crop() {
                if(!this.croppable) {
                    return
                }
                const croppedCanvas = this.cropper.getCroppedCanvas({
                    // 添加参数提升清晰度
                    width: 200,
                    height: 200,
                    imageSmoothingQuality: 'high'
                })
                const roundedCanvas = this.getRoundedCanvas(croppedCanvas)
                //       如果不需要请求接口可直接将url更新到视图
                this.headerImage = roundedCanvas.toDataURL()
    
                //       接口接收file内容的blob对象
                
              if (!HTMLCanvasElement.prototype.toBlob) {
                Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
                  value: function (callback, type, quality) {
                    var canvas = this;
                    setTimeout(function () {
                      var binStr = atob(canvas.toDataURL(type, quality).split(',')[1]);
                              var len = binStr.length;
                              var arr = new Uint8Array(len);
                              for (var i = 0; i < len; i++) {
                                arr[i] = binStr.charCodeAt(i);
                              }
     
                              callback(new Blob([arr], { type: type || 'image/png' }));
                    });
                  }
                });
              }
              let bold=this.dataURLtoBlob(this.headerImage)
              let resFile = this.blobToFile(bold, 'filename_' + Math.random(5));
                //传递给父组件,向后端提交
                var datas = {
                        img: this.headerImage,
                        file: resFile
                }
                this.$emit('to-parent', datas)
                //下面写法不兼容ie
    //          roundedCanvas.toBlob((data) => {
    //              var fileName=new Date().getTime()+'.png'
    //              const file = new File([data], fileName, {
    //                  type: 'image/png'
    //              })
    //              //传递给父组件,向后端提交
    //              var datas = {
    //                  img: this.headerImage,
    //                  file: file
    //              }
    //              this.$emit('to-parent', datas)
    //          })
                this.dialogVisible = false
            },
    //      base64 转 Blob
            dataURLtoBlob(toDataURL) {
                            var arr = toDataURL.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
                            });
                        },
            //转成file
            blobToFile(Blob, fileName) {
                            Blob.lastModifiedDate = new Date();
                            Blob.name = fileName;
                            return Blob;
                    },
            getRoundedCanvas(sourceCanvas) {
                const canvas = document.createElement('canvas')
                const context = canvas.getContext('2d')
                const width = sourceCanvas.width
                const height = sourceCanvas.height
    
                canvas.width = Math.min(300, width)
                canvas.height = Math.min(300, height)
    
                context.imageSmoothingEnabled = true
                // context.drawImage(sourceCanvas, 0, 0, width, height)  
                // 原图过大导致上传读取慢,截取300*300的尺寸
                context.drawImage(sourceCanvas, 0, 0, width, height, 0, 0, canvas.width, canvas.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
            },
            // 触发上传
            handleAdd() {
                this.$refs.inputFile.dispatchEvent(new MouseEvent('click'))
            },
        }
    }
    </script>
    
    <style lang="scss">
        .Upload {
            .el-dialog__body {
                padding-bottom: 0;
            }
            .yulan img {
                width: 200px;
                height: 200px;
                margin: 20px 0;
            }
            .small {
                width: 200px;
                height: 200px;
                overflow: hidden;
                margin: 0 auto;
                margin-top: 20px;
                border-radius: 50%;
                img {
                    /*border-radius: 50%;*/
                }
            }
            position: relative;
            .handle_add {
                display: none;
            }
            .container {
                width: 100%;
            }
            #image {
                max-width: 100%;
                height: 300px;
            }
        }
        
        .cropper-view-box,
        .cropper-face {
            border-radius: 50%;
        }
        /*!
       * Cropper.js v1.0.0-rc
       * https://github.com/fengyuanchen/cropperjs
       *
       * Copyright (c) 2017 Fengyuan Chen
       * Released under the MIT license
       *
       * Date: 2017-03-25T12:02:21.062Z
       */
        
        .cropper-container {
            font-size: 0;
            line-height: 0;
            position: relative;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            direction: ltr;
            -ms-touch-action: none;
            touch-action: none
        }
        
        .cropper-container img {
            /* Avoid margin top issue (Occur only when margin-top <= -height) */
            display: block;
            min-width: 0 !important;
            max-width: none !important;
            min-height: 0 !important;
            max-height: none !important;
            width: 100%;
            height: 100%;
            image-orientation: 0deg
        }
        
        .cropper-wrap-box,
        .cropper-canvas,
        .cropper-drag-box,
        .cropper-crop-box,
        .cropper-modal {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
        
        .cropper-wrap-box {
            overflow: hidden;
        }
        
        .cropper-drag-box {
            opacity: 0;
            background: #fff;
        }
        
        .cropper-modal {
            opacity: .5;
            background: #FFFFFF;
        }
        
        .cropper-view-box {
            display: block;
            overflow: hidden;
            width: 100%;
            height: 100%;
            outline: 1px solid #39f;
            outline-color: rgba(51, 153, 255, 0.75);
        }
        
        .cropper-dashed {
            position: absolute;
            display: block;
            opacity: .5;
            border: 0 dashed #eee
        }
        
        .cropper-dashed.dashed-h {
            top: 33.33333%;
            left: 0;
            width: 100%;
            height: 33.33333%;
            border-top-width: 1px;
            border-bottom-width: 1px
        }
        
        .cropper-dashed.dashed-v {
            top: 0;
            left: 33.33333%;
            width: 33.33333%;
            height: 100%;
            border-right-width: 1px;
            border-left-width: 1px
        }
        
        .cropper-center {
            position: absolute;
            top: 50%;
            left: 50%;
            display: block;
            width: 0;
            height: 0;
            opacity: .75
        }
        
        .cropper-center:before,
        .cropper-center:after {
            position: absolute;
            display: block;
            content: ' ';
            /* #eee */
        }
        
        .cropper-center:before {
            top: 0;
            left: -3px;
            width: 7px;
            height: 1px
        }
        
        .cropper-center:after {
            top: -3px;
            left: 0;
            width: 1px;
            height: 7px
        }
        
        .cropper-face,
        .cropper-line,
        .cropper-point {
            position: absolute;
            display: block;
            width: 100%;
            height: 100%;
            opacity: .1;
        }
        
        .cropper-face {
            top: 0;
            left: 0;
            /* #fff; */
        }
        
        .cropper-line.line-e {
            top: 0;
            right: -3px;
            width: 5px;
            cursor: e-resize
        }
        
        .cropper-line.line-n {
            top: -3px;
            left: 0;
            height: 5px;
            cursor: n-resize
        }
        
        .cropper-line.line-w {
            top: 0;
            left: -3px;
            width: 5px;
            cursor: w-resize
        }
        
        .cropper-line.line-s {
            bottom: -3px;
            left: 0;
            height: 5px;
            cursor: s-resize
        }
        
        .cropper-point {
            width: 5px;
            height: 5px;
            opacity: .75;
            /* #39f */
        }
        
        .cropper-point.point-e {
            top: 50%;
            right: -3px;
            margin-top: -3px;
            cursor: e-resize
        }
        
        .cropper-point.point-n {
            top: -3px;
            left: 50%;
            margin-left: -3px;
            cursor: n-resize
        }
        
        .cropper-point.point-w {
            top: 50%;
            left: -3px;
            margin-top: -3px;
            cursor: w-resize
        }
        
        .cropper-point.point-s {
            bottom: -3px;
            left: 50%;
            margin-left: -3px;
            cursor: s-resize
        }
        
        .cropper-point.point-ne {
            top: -3px;
            right: -3px;
            cursor: ne-resize
        }
        
        .cropper-point.point-nw {
            top: -3px;
            left: -3px;
            cursor: nw-resize
        }
        
        .cropper-point.point-sw {
            bottom: -3px;
            left: -3px;
            cursor: sw-resize
        }
        
        .cropper-point.point-se {
            right: -3px;
            bottom: -3px;
            width: 20px;
            height: 20px;
            cursor: se-resize;
            opacity: 1
        }
        
        @media (min-width: 768px) {
            .cropper-point.point-se {
                width: 15px;
                height: 15px
            }
        }
        
        @media (min-width: 992px) {
            .cropper-point.point-se {
                width: 10px;
                height: 10px
            }
        }
        
        @media (min-width: 1200px) {
            .cropper-point.point-se {
                width: 5px;
                height: 5px;
                opacity: .75
            }
        }
        
        .cropper-point.point-se:before {
            position: absolute;
            right: -50%;
            bottom: -50%;
            display: block;
            width: 200%;
            height: 200%;
            content: ' ';
            opacity: 0;
            /* #39f */
        }
        
        .cropper-invisible {
            opacity: 0;
        }
        
        .cropper-bg {
            background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMzTjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC');
        }
        
        .cropper-hide {
            position: absolute;
            display: block;
            width: 0;
            height: 0;
        }
        
        .cropper-hidden {
            display: none !important;
        }
        
        .cropper-move {
            cursor: move;
        }
        
        .cropper-crop {
            cursor: crosshair;
        }
        
        .cropper-disabled .cropper-drag-box,
        .cropper-disabled .cropper-face,
        .cropper-disabled .cropper-line,
        .cropper-disabled .cropper-point {
            cursor: not-allowed;
        }
    </style>
    

    3.在你想要使用的页面中调用

    <!--头像裁剪-->
          <Cropper ref="Cropper" @to-parent="childData"/>
    import Cropper from "@/components/component/cropper.vue"
    components:{Cropper},
    
    

    方法:

    //点击调用头像裁剪
        selectPhotos(){
             this.$refs.Cropper.dialogChange();
        },
        //获取裁剪图片数据
        childData(data){
            this.form.headImg=data.img;
            this.file=data.file;
        },
    

    相关文章

      网友评论

        本文标题:vue中使用cropperjs实现上传头像并裁剪

        本文链接:https://www.haomeiwen.com/subject/drmjhltx.html