【vue2+elementUI】图片上传和上传前尺校验和裁剪功能的实现

裁剪和上传图片

上传图片组件

通过el-upload组件的 :before-upload="beforeUpload"进行图片的上传前校验,:http-request进行自定义上传,在这里是通过裁剪弹框的确定按钮最终上传图片,不通过el-upload上传,所以:http-request="httpRequest"其实不生效

	<template slot="iconForm">
        <el-upload
          class="avatar-uploader"
          :before-upload="beforeUpload"
          :http-request="httpRequest"
          :on-success="handleAvatarSuccess"
          :show-file-list="false">
          //有图片时显示上传图片
          <img v-if="form.icon" :src="form.icon" alt="icon" class="avatar" />
          //无图片时显示默认图标
          <em v-else class="el-icon-plus avatar-uploader-icon"></em>
          //修改和新增转态显示
          <div v-if="tipShow" slot="tip" class="el-upload__tip">尺寸应为 82 * 82, 且不超过 500 k 的 jpg / png 文件</div>
          //删除
          <div v-if="form.icon && formType === 'edit'" class="uploader-operate" @click.stop="form.icon = ''">
            <em style="margin-left: 20px" class="el-icon-delete"></em>
          </div>
        </el-upload>
    </template>

裁剪弹框

	<el-dialog title="图片裁剪预览" append-to-body :visible.sync="showImageCropper" width="40%">
      <vueCropper
        ref="cropper"
        style="height: 400px"
       	//截图框移动
        :can-move="option.canMove"
        //截图框拖动
        :can-move-box="option.canMoveBox"
        :fixed-box="option.fixedBox"
        :img="cropOption.image"
        :fixed="cropOption.fixed"
        :height="cropOption.height"
        :outputSize="cropOption.size"
        :outputType="cropOption.type"
        :autoCrop="cropOption.autoCrop"
        :autoCropWidth="cropOption.autoCropWidth"
        :autoCropHeight="cropOption.autoCropHeight"
        :original="cropOption.original"></vueCropper>
      <span slot="footer" class="dialog-footer">
      //点击确定上传图片
        <el-button type="primary" @click="imageCropper">确 定</el-button>
      </span>
    </el-dialog>

在data里定义裁剪弹框的参数项,image是传入裁剪图片的地址:

 cropOption: {
  	 image: '',
     size: 1,
     type: 'png',
     height: true,
     fixed: true,
     autoCrop: true,
     autoCropWidth: 82,
     autoCropHeight: 82,
     original: true,
   },

上传前校验

简单校验下图片类型和大小,生成上传图片的url后给裁剪框image传入,确保裁剪框打开时有图片显示和裁剪:

其中window.URL.createObjectURL(file)用于创建一个
DOMString,其中包含一个表示参数中给出的对象(在这个案例中是一个文件对象)的URL。这个URL的生命周期和创建它的窗口中的
document 绑定,这个新的对象URL指向的是被传入的File对象或Blob对象。

 beforeUpload(file) {
      // 上传前校验
      const isJPG = ['image/jpeg', 'image/jpg', 'image/png'].includes(file.type);
      const isLt500k = file.size / 1024 / 1024 < 0.5;
      if (!isJPG) {
        this.$message.warning('外部图标只能是 jpg / png 格式');
        return false;
      }
      if (!isLt500k) {
        this.$message.warning('外部图标大小不能超过 500k');
        return false;
      }
      this.cropOption.image = window.URL.createObjectURL(file);
      // 打开裁剪框
      this.showImageCropper = true;

裁剪并上传图片

通过vueCropper的getCropBlob()获取裁剪后图片的Blob数据,然后处理成File对象,将file对象以formData 键值对格式传给接口,完成图片裁剪后的上传:

 // 裁剪并上传图片
    imageCropper() {
    //获取裁剪框的图片信息
      this.$refs.cropper.getCropBlob(data => {
        const file = new File([data], 'icon.png', {
          type: data.type,
          lastModified: Date.now(),
        });
        //格式化图片
        const formData = new FormData();
        //添加属性
        formData.append('file', file, file.name);
        const loading = this.$loading({
          lock: true,
          text: '图片上传中, 请稍后...',
          spinner: 'el-icon-loading',
        });
        //请求接口
        axios
          .post('/api/spang-system/oss/endpoint/put-file', formData, {
            headers: { 'Content-Type': 'multipart/form-data' },
          })
          .then(res => {
            loading.close();
            if (res.status && res.status === 200) {
              this.$set(this.form, 'icon', res.data.data.link);
              this.showImageCropper = false;
            }
          })
          .catch(e => {
            loading.close();
            this.$message.error(`图片上传失败!${JSON.stringify(e)}`);
          })
          .finally(() => {
            loading.close();
          });
      });
    },

效果展示

在这里插入图片描述

控制台问题和解决方法

上文提到,el-upload的:http-request可以进行自定义上传,但是在本次业务中,不需要通过el-upload上传,通过裁剪框的确定按钮上传,所以:http-request="httpRequest"其实不生效,但是在实际运行中,upload组件会在选择上传图片后默认调用一次http-request的方法进行上传

  • 尝试:设置 action=" "不生效,会将页面路由作为上传图片的接口调用
    在这里插入图片描述
  • 解决方法:自定义重置 httpRequest——:http-request=“httpRequest”,选择上传文件后进入该方法,返回false,不调用接口即可:
 //覆盖默认上传,走裁剪的上传文件,不走组件自带
    httpRequest() {
      return false;
    },

校验图片尺寸无裁剪直接上传

添加尺寸校验

beforeUpload里校验图片尺寸,符合校验的调用imageCropper()传入上传图片,对文件进行数据处理后再上传:

const isSize = new Promise(function (resolve, reject) {
        const width = 82; // 限制图片尺寸
        const height = 82;
        const URL = window.URL || window.webkitURL;
        const img = new Image();
        img.onload = function () {
          const valid = img.width === width && img.height === height;
          valid ? resolve() : reject();
        };
        img.src = URL.createObjectURL(file);
      }).then(
      //valid为true时调用resolve()
        () => {
          return true;
        },
       //valid为false时调用reject()
        () => {
          this.$message.warning('外部图标尺寸应为 82 * 82');
          return false;
        }
      );
      isSize.then(res => {
        console.log('res', res);
        if (isJPG && isLt500k && res) {
          this.imageCropper(file);
        }
      });
      console.log(isSize);

需要注意的是, isSize返回的是promise对象,valid为true时返回值是true,valid为false时返回值是false,如果直接判断isSize来调用this.imageCropper(file),判断不生效,因为不是直接返回true/false,是Promise对象,会一直判断为true,都会执行上传操作,如果是不符合尺寸的图片会提示尺寸不符合,但仍会成功上传
在这里插入图片描述
所以通过then方法来取到我们所需要的PromiseResult值,PromiseResult就是返回的Promise对象返回的布尔值,如下:

isSize.then(res => {
        console.log('res', res);
        if (isJPG && isLt500k && res) {
          this.imageCropper(file);
        }
      });
    },

在then函数中,拿到 PromiseResult的值后直接进行上传判断即可。

上传时获取图片并处理

不需要裁剪框,先注释掉裁剪框相关代码(vueCropper组件、打开和关闭弹框操作),之前是通过裁剪框的确定按钮上传图片,现在取消了裁剪框,要怎么上传图片呢?在上传前的尺寸校验时,符合要求尺寸时将file文件作为参数传入imageCropper,在imageCropper中对文件进行格式处理,最后调用上传文件接口时传入。
beforeUpload中传入上传图片:

this.imageCropper(file);
  • beforeUpload(file)——upload组件自带API,参数file,就是选择上传的图片文件,通过file可以直接获取
  • getCropBlob()是获取裁剪后图片的Blob数据,然后处理成File对象,将file对象以formData 键值对格式传给接口,此时不需要通过裁剪组件获取上传文件,去掉这块代码,直接对upload自带的 beforeUpload(file)传入imageCropper方法的参数进行处理就可以
imageCropper() {
      this.$refs.cropper.getCropBlob(data => {
        const file = new File([data], 'icon.png', {
          type: data.type,
          lastModified: Date.now(),
        });
 const formData = new FormData();
 formData.append('file', file, file.name);

这样就可以成功上传了,不符合尺寸时会提示尺寸问题,不会再上传:
不符合尺寸会提示,不会上传

效果展示

在这里插入图片描述

完整代码

最终的上传和校验代码如下:

 //上传图片
    imageCropper(file) {
      const formData = new FormData();
      formData.append('file', file, file.name);
      const loading = this.$loading({
        lock: true,
        text: '图片上传中, 请稍后...',
        spinner: 'el-icon-loading',
      });
      axios
        .post('/api/spang-system/oss/endpoint/put-file', formData, {
          headers: { 'Content-Type': 'multipart/form-data' },
        })
        .then(res => {
          loading.close();
          if (res.status && res.status === 200) {
            this.$set(this.form, 'icon', res.data.data.link);
            this.showImageCropper = false;
          }
        })
        .catch(e => {
          loading.close();
          this.$message.error(`图片上传失败!${JSON.stringify(e)}`);
        })
        .finally(() => {
          loading.close();
        });
    },
    // 图片上传前校验
    beforeUpload(file) {
      const isJPG = ['image/jpeg', 'image/jpg', 'image/png'].includes(file.type);
      const isLt500k = file.size / 1024 / 1024 < 0.5;
      if (!isJPG) {
        this.$message.warning('外部图标只能是 jpg / png 格式');
        return false;
      }
      if (!isLt500k) {
        this.$message.warning('外部图标大小不能超过 500k');
        return false;
      }
      const isSize = new Promise(function (resolve, reject) {
        const width = 82; // 限制图片尺寸为
        const height = 82;
        const URL = window.URL || window.webkitURL;
        const img = new Image();
        img.onload = function () {
          const valid = img.width === width && img.height === height;
          valid ? resolve() : reject();
        };
        img.src = URL.createObjectURL(file);
      }).then(
        () => {
          return true;
        },
        () => {
          this.$message.warning('外部图标尺寸应为 82 * 82');
          return false;
        }
      );
      console.log('isSize', isSize);
      isSize.then(res => {
        console.log('res', res);
        if (isJPG && isLt500k && res) {
          this.imageCropper(file);
        }
      });
    },
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值