使用ant-design-vue和vue-cropper实现裁剪图片并上传到服务器

安装vue-cropper

npm install vue-cropper

在main.js里面使用

import VueCropper from 'vue-cropper'
Vue.use(VueCropper)

需求:

用户上传图片后,需要裁剪,并保留,上传到服务器

思路:

点击上传,从本地选择图片文件
选择文件后弹出模态框(将选择的图片传递过去) 模态框作为裁剪图片的容器
进行裁剪
获取裁剪后的结果 并将裁剪后的图片上传到服务器,返回图片地址给父组件
父组件获取到裁剪后的图片地址后将图片回显

图片上传框组件

<template>
	<div class="ant-upload-preview">
		<div style="width: 100%">
			<a-upload
			name="avatar"
			:showUploadList="false"
			:beforeUpload="beforeUpload"
			:customRequest="function(){}"
			@change="handleChange"
			>
				<a-icon type="cloud-upload-o" class="upload-icon"/>
				<div class="mask">
				<a-icon type="plus"/>
				</div>
				<img :src="imageUrl" width="180px" height="180px"/>
			</a-upload>
		</div>
	</div>
	<!-- modal -->
    <cropper-modal ref="CropperModal" @ok="handleCropperSuccess"></cropper-modal>
</template>
<script>
  import CropperModal from './CropperModal'
export default {
    components: {
      CropperModal
    },
    props: {
      //图片格式
      imgFormat: {
        type: Array,
        default: function() {
          return ['image/jpeg']
        }
      },
      //图片大小
      imgSize: {
        type: Number,
        default: 2
      },
      //图片裁切配置
      options: {
        type: Object,
        default: function() {
          return {
            autoCropWidth: 180,
            autoCropHeight: 180
          }
        }
      },
      //回显图片路径
      value: {
        type: String,
        default: ''
      }
    },
    data() {
      return {
        loading: false,
        imageUrl: '',
      }
    },
    watch: {
      value: {
        handler(val) {
          this.imageUrl = val || ''
        },
        immediate: true
      }
    },

    methods: {
      //从本地选择文件
      handleChange(info) {
        let { options } = this
        this.getBase64(info.file.originFileObj, (imageUrl) => {
          let target = Object.assign({}, options, {
            img: imageUrl
          })
          this.$refs.CropperModal.edit(target)
        })
      },
      // 上传之前 格式与大小校验
      beforeUpload(file) {
        var fileType = file.type
        if (fileType.indexOf('image') < 0) {
          this.$message.warning('请上传图片')
          return false
        }
      },
      //裁剪成功后的File对象
      handleCropperSuccess(data) {
        //进行图片上传动作
        // 模拟后端请求 2000 毫秒延迟
        let that = this
        //将返回的数据回显
        that.imageUrl = window._CONFIG['imgDomainURL'] + '/' + data
        that.avatar = data
      },
      getBase64(img, callback) {
        const reader = new FileReader()
        reader.addEventListener('load', () => callback(reader.result))
        reader.readAsDataURL(img)
      }
    }
  }
</script>

<style lang="scss" scoped>

  .avatar-upload-wrapper {
    height: 180px;
    width: 100%;
  }

  .ant-upload-preview {
    position: relative;
    margin: 0 auto;
    width: 100%;
    max-width: 180px;
    border-radius: 50%;
    box-shadow: 0 0 4px #ccc;

    .upload-icon {
      position: absolute;
      top: 0;
      right: 10px;
      font-size: 1.4rem;
      padding: 0.5rem;
      background: rgba(222, 221, 221, 0.7);
      border-radius: 50%;
      border: 1px solid rgba(0, 0, 0, 0.2);
    }

    .mask {
      opacity: 0;
      position: absolute;
      background: rgba(0, 0, 0, 0.4);
      cursor: pointer;
      transition: opacity 0.4s;

      &:hover {
        opacity: 1;
      }

      i {
        font-size: 2rem;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-left: -1rem;
        margin-top: -1rem;
        color: #d6d6d6;
      }
    }

    img, .mask {
      width: 180px;
      height: 180px;
      border-radius: 50%;
      overflow: hidden;
    }
  }
</style>

模态框

<template>
  <a-modal
    :visible="visible"
    title="修改头像"
    :maskClosable="false"
    :confirmLoading="confirmLoading"
    :width="800"
    @cancel="cancelHandel">
    <a-row>
      <a-col :xs="24" :md="12" :style="{height: '350px'}">
        <vue-cropper
          ref="cropper"
          :img="options.img"
          :info="true"
          :autoCrop="options.autoCrop"
          :autoCropWidth="options.autoCropWidth"
          :autoCropHeight="options.autoCropHeight"
          :fixedBox="options.fixedBox"
          @realTime="realTime"
        >
        </vue-cropper>
      </a-col>
      <a-col :xs="24" :md="12" :style="{height: '350px'}">
        <div class="avatar-upload-preview">
          <img :src="previews.url" :style="previews.img"/>
        </div>
      </a-col>
    </a-row>
    <template slot="footer">
      <a-button key="back" @click="cancelHandel">取消</a-button>
      <a-button key="submit" type="primary" :loading="confirmLoading" @click="okHandel">保存</a-button>
    </template>
  </a-modal>
</template>
<script>
  import { VueCropper } from 'vue-cropper'
  
  export default {
    name: 'cropperModal',
    components: {
      VueCropper
    },
    data() {
      return {
        visible: false,
        img: null,
        confirmLoading: false,

        options: {
          img: window._CONFIG['imgDomainURL'] + '/' + Vue.ls.get(USER_INFO).avatar,//裁剪图片的地址
          autoCrop: true, //是否默认生成截图框
          autoCropWidth: 200, //默认生成截图框宽度
          autoCropHeight: 200, //默认生成截图框高度
          fixedBox: true //固定截图框大小 不允许改变
        },
        previews: {},
        url:{
          upload:'/sys/common/saveToImgByStr'
        }
      }
    },
    methods: {
      edit(record) {
        console.log(record)
        let { options } = this
        this.visible = true
        this.options = Object.assign({}, options, record)
      },
      cancelHandel() {
        this.options = {
          img: './avatar2.jpg',
          autoCrop: true,
          autoCropWidth: 200,
          autoCropHeight: 200,
          fixedBox: true
        }
        this.confirmLoading = false
        this.visible = false
      },
      okHandel() {
        const that = this
        that.confirmLoading = true
        // 获取截图的base64 数据
        this.$refs.cropper.getCropData((data) => {
          var file={
            imgByte:data
          }
          axios({
            url:that.url.upload,
            method: 'post',
            data: file,
            headers:{
              'Content-Type':'application/json'
            }
          }).then((res)=>{
            that.$emit('ok', res.message)
            that.cancelHandel()
          })
        })
      },
      //移动框的事件
      realTime(data) {
        this.previews = data
      },
    }
  }
</script>

<style lang="scss" scoped>
  .avatar-upload-preview {
    position: absolute;
    top: 50%;
    transform: translate(50%, -50%);
    width: 180px;
    height: 180px;
    border-radius: 50%;
    box-shadow: 0 0 4px #ccc;
    overflow: hidden;

    img {
      width: 100%;
      height: 100%;
    }
  }

</style>

你可能感兴趣的:(vue-cropper)