elementui+upload+VueCropper

效果图

在这里插入图片描述

npm install vue-cropper

  • 新建一个图片剪裁的组件 img-cropper
<template>
  <div class="vue-cropper-box">
    <div class="vue-cropper-operate">
      <button class="basicButton" @click="cropperChangeScale(1)">放大</button>
      <button class="basicButton" @click="cropperChangeScale(-1)">缩小</button>
      <button class="basicButton" @click="cropperRotateLeft">左旋转</button>
      <button class="basicButton" @click="cropperRotateRight">右旋转</button>
      <button class="basicButton" @click="cropperDown('blob')">下载</button> 
      <button class="basicButton" @click="cropperFinish('Blob')">确定裁剪</button>
    </div>
    <div class="vue-cropper-content" style="width:100%;height:310px">
      <VueCropper ref="cropper" :img="img" :outputSize="cropperOption.outputSize" :outputType="outputType" :info="cropperOption.info" :full="cropperOption.full" :canMove="cropperOption.canMoveBox" :canMoveBox="cropperOption.canMoveBox" :original="cropperOption.original" :canScale="cropperOption.canScale" :autoCrop="true" :fixedBox="true" :fixed="cropperOption.fixed" :fixedNumber="fixedNumber" :centerBox="cropperOption.centerBox" :infoTrue="cropperOption.infoTrue" @realTime="realTime" @imgLoad="imgLoad"></VueCropper>
    </div>
  </div>
</template>
<script>
import { VueCropper } from 'vue-cropper'
export default {
  name: 'img-cropper',
  components: { VueCropper },
  // inject: ['reload'],
  filters: {},
  props: {
    file: {
      default: () => { },
      required: true
    },
    img: {
      default: "",
      required: true
    },
    fixedNumber: {  //截图框的宽高比例
      type: Array,
      required: true
    },
    outputType: {  //截图框的宽高比例
      type: String,
      required: true
    },
    cropperOption: {
      default: () => ({
        // img: '', // 裁剪图片的地址
        info: true, // 裁剪框的大小信息
        outputSize: 0.8, // 裁剪生成图片的质量
        // outputType: '', // 裁剪生成图片的格式
        canScale: true, // 图片是否允许滚轮缩放
        autoCrop: true, // 是否默认生成截图框
        // autoCropWidth: 300, // 默认生成截图框宽度
        // autoCropHeight: 200, // 默认生成截图框高度
        fixedBox: true, // 固定截图框大小 不允许改变
        fixed: true, // 是否开启截图框宽高固定比例
        // fixedNumber: [12, 5], // 截图框的宽高比例
        full: true, // 是否输出原图比例的截图
        canMoveBox: true, // 截图框能否拖动
        original: false, // 上传图片按照原始比例渲染
        centerBox: false, // 截图框是否被限制在图片里面
        infoTrue: true // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
      })
    }
  },
  data () {
    return {
    };
  },
  computed: {
    // computeFunction() {
    //     return value;
    // }
  },
  watch: {
  },
  created () {
    // this.init();
  },
  mounted () {
    this.init();
  },
  methods: {
    init () {
      this.cropperOption.img = this.file
    },

    cropperChangeScale (num) {
      num = num || 1;
      this.$refs.cropper.changeScale(num);
    },

    // 左旋转
    cropperRotateLeft () {
      this.$refs.cropper.rotateLeft();
    },

    // 右旋转
    cropperRotateRight () {
      this.$refs.cropper.rotateRight();
    },

    // 下载图片
    cropperDown (type) {
      let aLink = document.createElement('a');
      aLink.download = 'author-img';
      if (type === 'blob') {
        this.$refs.cropper.getCropBlob(data => {
          this.downImg = window.URL.createObjectURL(data);
          aLink.href = window.URL.createObjectURL(data);
          aLink.click();
        });
      } else {
        this.$refs.cropper.getCropData(data => {
          this.downImg = data;
          aLink.href = data;
          aLink.click();
        });
      }
    },

    // 确定裁剪
    cropperFinish (type) {
      if (type === 'Blob') {
        this.$refs.cropper.getCropBlob((data) => { //这个方法将转成Blob对象
          console.log(data);
          let file = data;
          file.name = this.file.name;
          this.$emit('cropperFinish', file, data);
        });

      } else {
        this.$refs.cropper.getCropData(data => {    // 这个方法将转成base64格式
          // 将剪裁后base64的图片转化为file格式
          let file = this.convertBase64UrlToBlob(data);
          file.name = this.file.name;
          this.$emit('cropperFinish', file, data);
        });
      }

    },

    // 将base64的图片转换为file文件
    convertBase64UrlToBlob (urlData) {
      let bytes = window.atob(urlData.split(',')[1]); // 去掉url的头,并转换为byte
      // 转化为base64
      // reader.readAsDataURL(file)
      // 转化为blob
      // 处理异常,将ascii码小于0的转换为大于0
      let ab = new ArrayBuffer(bytes.length);
      let ia = new Uint8Array(ab);
      for (let i = 0; i < bytes.length; i++) {
        ia[i] = bytes.charCodeAt(i);
      }
      return new Blob([ab], { type: 'image/jpeg' });
    },

    // 实时预览函数
    realTime (data) {
      // console.log('realTime');
    },

    // 图片已加载
    imgLoad (msg) {
      // console.log('imgLoad');
      // console.log(msg);
    },
    close () {
      this.$emit('close');
    }
  }
};
</script>
<style lang="less" scope>
// 基础按钮
.basicButton {
  font-size: 16px;
  width: 100px;
  padding: 8px 10px;
  // line-height: 0.4rem;
  border: none;
  border-radius: 20px;
  color: #fff;
  background: #5cadff;
  outline: none;

  &:not(:last-child) {
    margin-right: 20px;
  }
}
.vue-cropper-header {
  .title {
    font-weight: 600;
    display: flex;
    justify-content: space-between;
    padding-top: 20px;
    margin-bottom: 10px;
    .ivu-icon .ivu-icon-ios-close {
      font-size: 20px;
    }
  }
}
/* 图片裁剪工具 */
.vue-cropper-box {
  z-index: 3001;
  // position: absolute;
  top: 0;
  background: #fff;

  .vue-cropper-operate {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.2rem;
  }

  .vue-cropper-content {
    position: relative;
    overflow-y: auto;

    .vue-cropper {
      position: absolute;
    }
  }
}
</style>
  • 新建一个elementui上传组件
<template>
  <div>
    <el-upload class="avatar-uploader" v-loading="loading" :action="action" :show-file-list="false" name="file" :http-request="picUpload" :before-upload="beforeUpload">
      <img v-if="imgList[0]" :src="imgList[0].url" class="avatar" />
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
  </div>
</template>
<script>
export default {
  props: {
    imgList: {
      type: Array,
      default () {
        return []
      }
    },
    limit: {
      type: Number
    }
  },
  data () {
    return {
      action: '上传地址',
      disabled: false,
      uploadData: {
        file: '',
        project: ''
      },
      loading: false,
      httpCtx: process.env.VUE_APP_httpCtx,
    }
  },
  computed: {
    // fileList () {
    //   const val = this.imgList
    //   const arr = []
    //   if (val && val.length > 0) {
    //     val.forEach(item => {
    //       const { name, path, url } = item
    //       let imgUrl = ''
    //       imgUrl = path
    //       if (url) {
    //         imgUrl = url
    //       }
    //       if (imgUrl.startsWith('http') || imgUrl.startsWith('https')) {
    //         arr.push({ name: name, url: imgUrl })
    //       } else {
    //         arr.push({ name: name, url: `${process.env.VUE_APP_httpCtx}${imgUrl}` })
    //       }
    //     })
    //     return arr
    //   } else {
    //     return []
    //   }
    // },
  },
  created () {
  },
  methods: {
    // 图片上传前触发裁剪组件
    // 将图片读出并在完成时触发裁剪
    picUpload (option) {
      let file = option.file
      let reader = new FileReader();
      if (file) {
        reader.readAsDataURL(file)
      }
      reader.onload = () => {
        let src = reader.result
        let obj = {
          cropperShow: true,
          cropperImg: src
        }
        this.$emit("modalShowFn", obj)
      }
    },
    handleRemove (file, fileList) {
      console.log(file, fileList);
      this.$emit('update:imgList', fileList);
    },
    handleExceed (files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.limit} 个文件,本次选择了 ${
        files.length
        } 个文件,共选择了 ${files.length + fileList.length} 个文件`
      );
    },
    beforeUpload (file) {
      const isLt10M = file.size / 1024 / 1024 < 10;
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/gif' || file.type === 'image/jpg' || file.type === 'image/bmp' || file.type === 'image/png';
      if (!isLt10M) {
        this.$message.error('上传图片大小不能超过 10MB!');
      }
      if (!isJPG) {
        this.$message.error('上传图片只能是 JPG/JPEG/GIF/BMP 格式!');
      }
      return isJPG && isLt10M;
    },
    handProcess (event, file) {
      this.loading = true;

    }
  }
}
</script>
<style scope>
.avatar-uploader .el-upload {
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  border: 1px solid #dcdee2;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 200px;
  height: 200px;
  line-height: 148px;
  text-align: center;
}
.avatar {
  width: 200px;
  height: 200px;
  display: block;
  position: relative;
  z-index: 99;
}
.el-icon-plus:before {
  line-height: 200px;
}
</style>
  • 页面中使用

可以引入组件或者注册全局组件

  <uploadImage :imgList.sync="addForm.cover" :limit="1" @modalShowFn="getModalStatus />

    <el-dialog title="图片剪裁" :visible.sync="isShowCropper" width="50%">
      <div class="cropperModalBody" style="width:100%;height:350px">
        <img-cropper :img="cropperImg" :fixedNumber="fixedNumber" :outputType="outputType" :file="cropperFile" @cropperFinish="postUploadFile" @close="()=>{isShowCropper=false}"></img-cropper>
      </div>
      <div slot="footer"></div>
    </el-dialog>

  • data中定义
      isShowCropper: false,
      cropperImg: "",
      cropperFile: {},
      httpCtx: process.env.VUE_APP_httpCtx,
      fixedNumber: [16, 15],
      outputType: 'jpeg',
  • methods中写下方法
 getModalStatus (obj) {
      this.cropperImg = obj.cropperImg;
      this.isShowCropper = obj.cropperShow;
    },

    // 文件上传-接口-上传文件
    async postUploadFile (blob) {
      let suffix = blob.type.split('/')[blob.type.split('/').length - 1]
      let filename = Date.parse(new Date()) / 1000 + '.' + suffix  //生成文件名
      //将blob转换为file
      let file = new File([blob], filename, { type: blob.type, lastModified: Date.now() });
      file.uid = Date.now();
      var fd = new FormData();
      fd.append("file", file, file.name);
      fd.append("imageType", "101");
      const res = await this.axios.uploadFiles(fd)
      if (res.code === 0) {
        this.addForm.cover = [{
          name: res.data[0].name,
          url: this.httpCtx + res.data[0].path,
        }]
        //  this.$refs.upload.clearFiles()
        this.isShowCropper = false;
        this.cropperImg = null;
        this.cropperFile = {};
      }
    },
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值