上传文件时候接到一个需求 商品必须为固定尺寸 在网上找的 基本在 before-upload 加限制条件没有根本的解决问题 于是想到裁剪后上传

elementui 格式化upload 文件展示 filelist vue element upload_宽高

之前上传文件的标签

<el-upload
                    class="avatar-uploader"
                    :headers="uploadHeaders"
                    :action="uploadUrl + '?updateSupport=' + 0"
                    :show-file-list="false"
                    :on-success="handleAvatarSuccess"
                    :before-upload="beforeAvatarUpload"
                  >
                    <img v-if="imageUrl" :src="imageUrl" class="avatar">
                    <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                    <template #tip>
                      <div class="el-upload__tip">可上传一张图片,140*140</div>
                    </template>
                  </el-upload>

 参考其他人想要实现自定义上传 需要修改  auto-upload:false http-request 自定义上传方法等

后来发现没有那么麻烦 仅保留before-upload即可 

<el-upload
                                    class="avatar-uploader"
                                    :action="''"
                                    :show-file-list="false"
                                    :before-upload="beforeAvatarUpload"
                            >
                                <img v-if="imageUrl" :src="imageUrl" class="avatar">
                                <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                                <template #tip>
                                    <div class="el-upload__tip">可上传一张图片,140*140</div>
                                </template>
                            </el-upload>

裁剪工具为 VueCropper 

elementui 格式化upload 文件展示 filelist vue element upload_vue.js_02

  •  安装 npm install vue-cropper // npm 安装
  • 局部引入并编写组件 (参考其他小伙伴进行修改)
<template>
    <div>
        <el-dialog
                title="图片剪裁"
                v-model="dialogVisiblex"
                :close-on-press-escape="false"
                :close-on-click-modal="false"
                append-to-body
                width="1000px"
        >
            <div class="cropper-content">
                <div class="cropper" style="text-align:center">
                    <vueCropper
                            ref="cropper"
                            :img="option.img"
                            :outputSize="option.outputSize"
                            :outputType="option.outputType"
                            :info="option.info"
                            :canScale="option.canScale"
                            :autoCrop="option.autoCrop"
                            :autoCropWidth="option.autoCropWidth"
                            :autoCropHeight="option.autoCropHeight"
                            :fixedBox="option.fixedBox"
                            :fixed="option.fixed"
                            :fixedNumber="option.fixedNumber"
                            :canMove="option.canMove"
                            :canMoveBox="option.canMoveBox"
                            :original="option.original"
                            :centerBox="option.centerBox"
                            :infoTrue="option.infoTrue"
                            :full="option.full"
                            :enlarge="option.enlarge"
                            :mode="option.mode"
                    >
                    </vueCropper>
                </div>
            </div>
            <template #footer class="dialog-footer">
                <el-button @click="dialogVisiblex = false">取消</el-button>
                <el-button type="primary" @click="finish" :loading="loading"
                >确认</el-button
                >
            </template>
        </el-dialog>
    </div>
</template>

<script>
    import VueCropper from "vue-cropper/src/vue-cropper.vue"

    export default {
        components: {VueCropper},
        props: {},
        data() {
            return {
                dialogVisiblex: false,
                loading: false,
                option: {
                    img: '', // 裁剪图片的地址 url 地址, base64, blob
                    outputSize: 1, // 裁剪生成图片的质量
                    outputType: 'jpeg', // 裁剪生成图片的格式 jpeg, png, webp
                    info: true, // 裁剪框的大小信息
                    canScale: true, // 图片是否允许滚轮缩放
                    autoCrop: true, // 是否默认生成截图框
                    autoCropWidth: 345, // 默认生成截图框宽度
                    autoCropHeight: 245, // 默认生成截图框高度
                    fixedBox: true, // 固定截图框大小 不允许改变
                    fixed: true, // 是否开启截图框宽高固定比例
                    fixedNumber: [1, 1], // 截图框的宽高比例 [ 宽度 , 高度 ]
                    canMove: true, // 上传图片是否可以移动
                    canMoveBox: true, // 截图框能否拖动
                    original: false, // 上传图片按照原始比例渲染
                    centerBox: true, // 截图框是否被限制在图片里面
                    infoTrue: true, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
                    full: true, // 是否输出原图比例的截图
                    enlarge: '1', // 图片根据截图框输出比例倍数
                    mode: 'contain' // 图片默认渲染方式 contain , cover, 100px, 100% auto
                },
                unimgurl: '',
                success: () => {} // 回调方法
            }
        },
        computed: {},
        watch: {},
        created() {

        },
        mounted() {},
        activated() {},
        methods: {
            showModal(obj) {
                if (obj.img) {
                    this.option.img = obj.img
                }
                //裁剪生成图片的质量
                if (obj.outputSize) {
                    this.option.outputSize = obj.outputSize
                } else {
                    this.option.outputSize = 1
                }
                //裁剪生成图片的格式
                if (obj.outputType) {
                    this.option.outputType = obj.outputType
                } else {
                    this.option.outputType = 'jpeg'
                }
                //裁剪框的大小信息
                if (obj.info) {
                    this.option.info = obj.info
                } else {
                    this.option.info = true
                }
                //图片是否允许滚轮缩放
                if (obj.canScale) {
                    this.option.canScale = obj.canScale
                } else {
                    this.option.canScale = true
                }
                //是否默认生成截图框
                if (obj.autoCrop) {
                    this.option.autoCrop = obj.autoCrop
                } else {
                    this.option.autoCrop = true
                }
                //默认生成截图框宽度
                if (obj.autoCropWidth) {
                    this.option.autoCropWidth = obj.autoCropWidth
                } else {
                    this.option.autoCropWidth = 375
                }
                //默认生成截图框高度
                if (obj.autoCropHeight) {
                    this.option.autoCropHeight = obj.autoCropHeight
                } else {
                    this.option.autoCropHeight = 245
                }
                //固定截图框大小 不允许改变
                if (obj.fixedBox) {
                    this.option.fixedBox = obj.fixedBox
                } else {
                    this.option.fixedBox = false
                }
                //是否开启截图框宽高固定比例
                if (obj.fixed) {
                    this.option.fixed = obj.fixed
                } else {
                    this.option.fixed = true
                }
                //截图框的宽高比例
                if (obj.fixedNumber) {
                    this.option.fixedNumber = obj.fixedNumber
                } else {
                    this.option.fixedNumber = [this.option.autoCropWidth, this.option.autoCropHeight]
                }
                //上传图片是否可以移动
                if (obj.canMove) {
                    this.option.canMove = obj.canMove
                } else {
                    this.option.canMove = true
                }
                //截图框能否拖动
                if (obj.canMoveBox) {
                    this.option.canMoveBox = obj.canMoveBox
                } else {
                    this.option.canMoveBox = true
                }
                //上传图片按照原始比例渲染
                if (obj.original) {
                    this.option.original = obj.original
                } else {
                    this.option.original = false
                }
                //截图框是否被限制在图片里面
                if (obj.centerBox) {
                    this.option.centerBox = obj.centerBox
                } else {
                    this.option.centerBox = true
                }
                //true 为展示真实输出图片宽高 false 展示看到的截图框宽高
                if (obj.infoTrue) {
                    this.option.infoTrue = obj.infoTrue
                } else {
                    this.option.infoTrue = true
                }
                //是否输出原图比例的截图
                if (obj.full) {
                    this.option.full = obj.full
                } else {
                    this.option.full = true
                }
                //图片根据截图框输出比例倍数
                if (obj.enlarge) {
                    this.option.enlarge = obj.enlarge
                } else {
                    this.option.enlarge = '1'
                }
                //图片默认渲染方式
                if (obj.mode) {
                    this.option.mode = obj.mode
                } else {
                    this.option.mode = 'contain'
                }
                if (obj.success) {
                    this.success = obj.success
                } else {
                    this.success = () => {}
                }
                this.dialogVisiblex = true
            },
            finish() {
                // 获取截图的数据
                let that = this
                this.$refs.cropper.getCropBlob(data => {
                    that.unimgurl = data
                    that.confirm()
                })
            },
            confirm() {
                this.success({
                    img: this.unimgurl
                })
                this.dialogVisiblex = false
            },
            cancel() {
                this.dialogVisiblex = false
            }
        }
    }
</script>
<style lang="scss" scoped></style>
<style lang="scss">
    .real_info_class {
        .el-checkbox__input .el-checkbox__inner {
            border-radius: 0;
        }
    }
    .file-image {
        width: 320px;
        height: 320px;
        font-size: 14px;
        border: 1px solid #cccccc;
        margin: 15px 0;
    }

    /* 截图 */
    /* .cropper-content {} */
    .cropper {
        width: 960px;
        height: 606px;
    }
</style>

注意引入方式为 

import VueCropper from "vue-cropper/src/vue-cropper.vue"

在upload标签下加上如下代码

elementui 格式化upload 文件展示 filelist vue element upload_vue.js_03

 下面贴出 完成的before-upload代码

beforeAvatarUpload(file) {
                let _this = this
                return new Promise((resolve, reject) => {
                    let types = ['image/jpeg', 'image/jpg', 'image/png'];
                    // let width = 140;
                    // let height = 140;
                    const isJPG = types.includes(file.type)
                    const isLt2M = file.size / 1024 / 1024 < 2
                    if (!isJPG) {
                        _this.$message.error('上传图片只能是 JPG 或 png格式!')
                        reject()
                    }
                    if (!isLt2M) {
                        _this.$message.error('上传图片大小不能超过 2MB!')
                        reject()
                    }


                    let _URL = window.URL || window.webkitURL;


                    //上传前对图片进行裁剪
                    _this.$refs.iscropper.showModal({
                        img: _URL.createObjectURL(file) , // 裁剪图片的地址
                        autoCropWidth: 140, // 默认生成截图框宽度
                        autoCropHeight: 140, // 默认生成截图框高度
                        fixedBox:true,
                        success: res => {
                            //拿到裁剪后图片没有name 属性
                            //file的name属性为只读 不能手动设置
                            //创建一个新的图片对象 设置原始文件名
                            const cloneFile = new File([res.img], file.name);

                            const formData = new FormData()
                            //   console.log(param.file)
                            //通过 append 函数往formdata对象里传参,这里传的是后端需求的接口信息
                            formData.append('file', cloneFile)

                            //执行上传操作
                            request({
                                method: "post",
                                url: "/sys/file/upload/productImage",
                                data: formData,
                                headers: { "Content-Type": "multipart/form-data" },

                            }).then(response => {
                                //请求成功
                                _this.handleAvatarSuccess(response,cloneFile)
                            })

                            resolve()
                        }
                    })
                })
}

讲一下大概的思路 

  1. 第一步照常对上传文件做一个限制
  2. 打开裁剪框 设置固定的裁剪大小 并设置滚动放大缩小图片
  3. 由于裁剪后的图片没有文件名 并且文件名是只读  所以创建一个新的图片对象 并将图片原始文件名设置
  4. 文件传输是通过formdata上传的 创建formdata对象 将图片放在formdata对象中
  5. 上传成功后图片进行回显 并将图片id回传到业务数据中
handleAvatarSuccess(res,file) {
                console.log(res)

                if(res.code == 2000){
                    this.$successmsg(res.msg)
                    this.imageUrl = URL.createObjectURL(file);
                    this.ruleForm.productImg = res.data.id
                }else{
                    this.$warnmsg(res.msg);
                    this.imageUrl = '';
                    this.ruleForm.productImg	 = ''
                }
            }

上传成功 后的操作 可根据自己 项目自定义 

最后的效果 

elementui 格式化upload 文件展示 filelist vue element upload_上传_04

保存在本地的图片

elementui 格式化upload 文件展示 filelist vue element upload_vue.js_05