VueCropper + Element上传并剪裁图片

VueCropper + Element 上传并剪裁图片

效果图

在这里插入图片描述
在这里插入图片描述

安装插件

npm install vue-cropper

VueCropper组件代码

<template>
  <div>
    <el-dialog title="图片剪裁" :visible.sync="cropperShow" append-to-body width="1000px" center>
      <div class="cropper-content">
        <div class="cropper-box">
          <div class="cropper">
            <vue-cropper ref="cropper" :img="img" :outputSize="option.outputSize" :outputType="option.outputType" :info="option.info" :canScale="option.canScale" :autoCrop="option.autoCrop" :autoCropWidth="autoCropWidth" :autoCropHeight="autoCropHeight" :fixed="option.fixed" :fixedNumber="option.fixedNumber" :full="option.full" :fixedBox="fixedBox" :canMove="option.canMove" :canMoveBox="option.canMoveBox" :original="option.original" :centerBox="option.centerBox" :height="option.height" :infoTrue="option.infoTrue" :maxImgSize="option.maxImgSize" :enlarge="option.enlarge" :mode="option.mode" @realTime="realTime" @imgLoad="imgLoad">
            </vue-cropper>
          </div>
          <!--底部操作工具按钮-->
          <div class="footer-btn">
            <div class="scope-btn">
              <el-button size="mini" type="danger" plain icon="el-icon-zoom-in" @click="changeScale(1)">放大</el-button>
              <el-button size="mini" type="danger" plain icon="el-icon-zoom-out" @click="changeScale(-1)">缩小</el-button>
              <el-button size="mini" type="danger" plain @click="rotateLeft">↺ 左旋转</el-button>
              <el-button size="mini" type="danger" plain @click="rotateRight">↻ 右旋转</el-button>
            </div>
            <div class="upload-btn">
              <el-button size="mini" type="success" @click="uploadImg('blob')">上传图片 <i class="el-icon-upload"></i></el-button>
            </div>
          </div>
        </div>
        <!--预览效果图-->
        <div class="show-preview">
          <div :style="previews.div" class="preview">
            <img :src="previews.url" :style="previews.img">
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import {
      
       VueCropper } from 'vue-cropper'
import {
      
       cropperUpload } from '@/api/common'
export default {
      
      
  name: "CropperImage",
  components: {
      
      
    VueCropper
  },
  data () {
      
      
    return {
      
      
      show: this.cropperShow,
      previews: {
      
      },
      option: {
      
      
        // img: '',             //裁剪图片的地址
        outputSize: 1,       //裁剪生成图片的质量(可选0.1 - 1)
        outputType: 'jpeg',  //裁剪生成图片的格式(jpeg || png || webp)
        info: true,          //裁剪框的大小信息,图片大小信息
        canScale: true,      //图片是否允许滚轮缩放
        autoCrop: true,      //是否默认生成截图框
        // autoCropWidth: 300,  //默认生成截图框宽度
        // autoCropHeight: 200, //默认生成截图框高度
        fixed: false,         //是否开启截图框宽高固定比例
        fixedNumber: [1.5, 1], //截图框的宽高比例
        full: true,         //false按原比例裁切图片,不失真
        // fixedBox: false,      //固定截图框大小,不允许改变
        canMove: true,      //上传图片是否可以移动
        canMoveBox: true,    //截图框能否拖动
        original: false,     //上传图片按照原始比例渲染
        centerBox: false,    //截图框是否被限制在图片里面
        height: true,        //是否按照设备的dpr 输出等比例图片
        infoTrue: false,     //true为展示真实输出图片宽高,false展示看到的截图框宽高
        maxImgSize: 3000,    //限制图片最大宽度和高度
        enlarge: 1,          //图片根据截图框输出比例倍数
        // mode: '230px 150px'  //图片默认渲染方式
      }
    };
  },
  props: {
      
      
    cropperShow: {
      
      
      type: Boolean,
      default: false
    },
    img: {
      
      
      type: String,
      default: ''
    },
    autoCropWidth: {
      
      
      type: Number,
      default: 100
    },
    autoCropHeight: {
      
      
      type: Number,
      default: 100
    },
    fileinfo: {
      
      
      type: Object,
      default: null,
    },
    fixedBox: {
      
      
      type: Boolean,
      default: true
    }
  },
  methods: {
      
      
    //初始化函数
    imgLoad (msg) {
      
      
    },
    //图片缩放
    changeScale (num) {
      
      
      num = num || 1
      this.$refs.cropper.changeScale(num)
    },
    //向左旋转
    rotateLeft () {
      
      
      this.$refs.cropper.rotateLeft()
    },
    //向右旋转
    rotateRight () {
      
      
      this.$refs.cropper.rotateRight()
    },
    //实时预览函数
    realTime (data) {
      
      
      this.previews = data
    },
    //选择图片
    selectImg (e) {
      
      
      let file = e.target.files[0]
      if (!/\.(jpg|jpeg|png|JPG|PNG)$/.test(e.target.value)) {
      
      
        this.$message({
      
      
          message: '图片类型要求:jpeg、jpg、png',
          type: "error"
        });
        return false
      }
      //转化为blob
      let reader = new FileReader()
      reader.onload = (e) => {
      
      
        let data
        if (typeof e.target.result === 'object') {
      
      
          data = window.URL.createObjectURL(new Blob([e.target.result]))
        } else {
      
      
          data = e.target.result
        }
        this.option.img = data
      }
      //转化为base64
      reader.readAsDataURL(file)
    },
    //上传图片
    uploadImg (type) {
      
      
      let _this = this
      if (type === 'blob') {
      
      
        // 获取截图的blob数据
        this.$refs.cropper.getCropBlob(async (data) => {
      
      
          let previewImg = URL.createObjectURL(data)
          let formData = new FormData();
          let file_name = this.fileinfo.uid + this.fileinfo.name//重命名
          formData.append('file', data, file_name)
          // 调用上传图片接口
          cropperUpload(formData).then((result) => {
      
      
            console.log(result);
            let msg = {
      
      
              uploadImg: previewImg, // 本地地址
              dataImg: result.data.url  // 接口返回的线上地址
            }
            this.$emit("cropperImg", msg)
          }).catch((err) => {
      
      
            console.log(err);
          });
        })
      }
    }
  }
}
</script>
<style scoped lang="sass">
.cropper-content
  display: flex
  display: -webkit-flex
  justify-content: flex-end
  .cropper-box
    flex: 2
    width: 100%
    .cropper
      width: auto
      height: 400px

  .show-preview
    flex: 1
    -webkit-flex: 1
    display: flex
    display: -webkit-flex
    justify-content: center
    .preview
      margin-left: 20px
      overflow: hidden
      border: 1px solid #67c23a
      background: #cccccc

.footer-btn
  margin-top: 30px
  display: flex
  display: -webkit-flex
  justify-content: flex-end
  .scope-btn
    display: flex
    display: -webkit-flex
    justify-content: space-between
    padding-right: 10px

  .upload-btn
    flex: 1
    -webkit-flex: 1
    display: flex
    display: -webkit-flex
    justify-content: center

  .btn
    outline: none
    display: inline-block
    line-height: 1
    white-space: nowrap
    cursor: pointer
    -webkit-appearance: none
    text-align: center
    -webkit-box-sizing: border-box
    box-sizing: border-box
    outline: 0
    -webkit-transition: 0.1s
    transition: 0.1s
    font-weight: 500
    padding: 8px 15px
    font-size: 12px
    border-radius: 3px
    color: #fff
    background-color: #409eff
    border-color: #409eff
    margin-right: 10px
</style>

父组件使用

<el-form-item label="图片" prop="imageUrl">
	<el-upload class="avatar-uploader" :action="uploadUrl()" :headers="uploadHeaders" :show-file-list="false" :on-success="handleAvatarSuccess" :before-upload="beforeAvatarUpload" :auto-upload="false" :on-change="onChange">
		<img v-if="form.imageUrl" :src="form.imageUrl ? getImageUrl(form.imageUrl) : coverImg" class="avatar" alt="" />
		<i v-else class="el-icon-plus avatar-uploader-icon"></i>
	</el-upload>
	<cropper :cropperShow.sync="cropperShow" :fileinfo="fileinfo" :img="croperImg" :autoCropWidth="375" :autoCropHeight="211" @cropperImg="cropperImg"></cropper>
</el-form-item>
    getImageUrl (path) {
    
    
      return 地址前缀 + "/" + path;
    },
    handleAvatarSuccess (res, file) {
    
    
      this.coverImg = URL.createObjectURL(file.raw);
      this.form.imageUrl = res.data.url;
    },
    beforeAvatarUpload (file) {
    
    
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isLt2M) {
    
    
        this.$message.error('上传图片大小不能超过 2MB!');
      }
      return isLt2M;
    },
    onChange (file) {
    
    
      if (file.status == "ready") {
    
    
        this.croperImg = window.URL.createObjectURL(new Blob([file.raw]));
        this.fileinfo = file
        this.cropperShow = true
      }
    },
    cropperImg (val) {
    
    
      // console.log("剪裁后的图片",val);
      this.coverImg = val.uploadImg;
      this.form.imageUrl = val.dataImg;
      this.cropperShow = false
    },
.avatar-uploader .el-upload {
    
    
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
    
    
  border-color: #409eff;
}
.avatar-uploader-icon {
    
    
  font-size: 28px;
  color: #8c939d;
  width: 375px;
  height: 211px;
  line-height: 211px;
  text-align: center;
}
.avatar {
    
    
  width: 375px;
  height: 211px;
  display: block;
}

猜你喜欢

转载自blog.csdn.net/yangsi0706/article/details/124732202