欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

vue-cropper实现图片裁剪上传

程序员文章站 2022-04-09 09:14:06
...

1.图片裁剪组件photoCut.vue

<template>
  <div>
    <div class="info-item">
      <div class="line">
        <div class="cropper-content">
          <div class="cropper" style="text-align: center">
            <div v-show="!option.img" class="uploadimg">
              <div style="  padding-top: 20px;">
                <i class="ic-upload-cloud iconfont"/>
              </div>
              <div style="line-height:22px;color:#79818B;margin-top: -33px">
                支持jpg、png格式的图片,大小不超过2M
              </div>
              <div style="margin-top: 30px">
                <Button class="but" @click="newUpload">上传图片</Button>
                <input type="file" id="uploads" :value="imgFile" style="position:absolute; clip:rect(0 0 0 0);"
                       accept="image/png, image/jpeg,image/jpg" @change="uploadImg($event, 1)">
              </div>
            </div>
            <vueCropper
              v-show="option.img"
              ref="cropper"
              :img="option.img"
              :outputSize="option.size"
              :outputType="option.outputType"
              :info="option.info"
              :full="option.full"
              :canMove="option.canMove"
              :canMoveBox="option.canMoveBox"
              :canScale="option.canScale"
              :original="option.original"
              :autoCrop="option.autoCrop"
              :autoCropWidth="option.autoCropWidth"
              :autoCropHeight="option.autoCropHeight"
              :fixedBox="option.fixedBox"
              :centerBox="option.centerBox"
              :enlarge="option.enlarge"
              :mode="option.mode"
              @realTime="realTime"
              @imgLoad="imgLoad"
            ></vueCropper>
          </div>
          <div class="yulanimg" style="position: relative">
            <div v-show="option.img">
              <div class="show-preview" :style="previewStyle1" style="top: -63px;left: -60px;">
                <div :style="previews.div" class="preview">
                  <img v-show="option.img" :src="previews.url" :style="previews.img">
                </div>
              </div>
              <div class="show-preview" :style="previewStyle2" style="top: 29px;left: -60px;">
                <div :style="previews.div" class="preview">
                  <img v-show="option.img" :src="previews.url" :style="previews.img">
                </div>
              </div>
              <div class="show-preview" :style="previewStyle3" style="top: 100px;left: -60px;">
                <div :style="previews.div" class="preview">
                  <img v-show="option.img" :src="previews.url" :style="previews.img">
                </div>
              </div>
            </div>
            <div v-show="!option.img">
              <div class="imgdiv1">
              </div>
              <div class="imgdiv2">
              </div>
              <div class="imgdiv3">
              </div>
            </div>
            <div class="show-preview"
                 style="height: 40px;width: 100%;
                        top: 296px;
                        left: 0px;">
              <Button class="but" v-show="option.img" @click="newUpload">重新上传</Button>
              <div v-show="!option.img" style="font-size:12px;
                    line-height:22px;
                    color:rgba(139,148,165,1);">预览
              </div>
            </div>
          </div>
        </div>
      </div>
      <!--<input type="button" class="btn btn-blue" value="上传头像" @click="finish('blob')">-->
    </div>
    <div flex="main:center" style="margin: 30px 0px  0px;">
      <Button @click="cancel" class=" resetBtn" size="large" style="width: 76px">取消</Button>
      <Button @click="finish('blob')"  :loading="buttonLoading" type="primary" size="large"  style="width: 76px">保存</Button>
    </div>
  </div>
</template>

<script>
  import {VueCropper} from 'vue-cropper'
  import {Button, Icon} from "view-design"
  import {uploadImg}  from './api/index'

  export default {
    data() {
      return {
        buttonLoading:false,
        previewStyle1: {},
        previewStyle2: {},
        previewStyle3: {},
        headImg: '',
        //剪切图片上传
        crap: false,
        previews: {},
        option: {
          img: '',//裁剪图片的地址
          outputSize: 1, //剪切后的图片质量(0.1-1)
          outputType: 'png',//裁剪生成图片的格式
          info: true,//裁剪框的大小信息
          canScale: true,//图片是否允许滚轮缩放
          autoCrop: true,//是否默认生成截图框
          autoCropWidth: 250,//默认生成截图框宽度
          autoCropHeight: 250,//默认生成截图框高度
          //fixed	是否开启截图框宽高固定比例true
          //fixedNumber	截图框的宽高比例
          full: false,//输出原图比例截图 false
          fixedBox: true,//固定截图框大小 不允许改变
          canMove: true,//上传图片是否可以移动
          canMoveBox: false,//截图框能否拖动
          original: false,//上传图片按照原始比例渲染
          centerBox: false,// centerBox	截图框是否被限制在图片里面
          // high	是否按照设备的dpr 输出等比例图片
          infoTrue: true, // 为展示真实输出图片宽高 false 展示看到的截图框宽高
          // maxImgSize	限制图片最大宽度和高度
          enlarge: 0.5, //图片根据截图框输出比例倍数
          mode: 'contain'	//图片默认渲染方式
        },
        fileName: '',  //本机文件地址
        //downImg: '#',
        imgFile: '',
        //uploadImgRelaPath: '', //上传后的图片的地址(不带服务器域名)
      }
    },
    components: {
      VueCropper, Button, Icon
    },
    methods: {
      newUpload() {
        document.getElementById("uploads").click()
      },
      //上传图片(点击上传按钮)
      finish(type) {
        this.buttonLoading=true
        if (!this.fileName) {
          this.buttonLoading=false
          this.$Message.info("请上传logo!")
          return
        }
        if (type === 'blob') {
          // 获取截图的blob数据
          this.$refs.cropper.getCropBlob((data) => {
            // let img = window.URL.createObjectURL(data)
            // this.model = true;
            // this.modelSrc = img;
            //裁剪后的图片显示
            // this.option.img = this.modelSrc;
            var forms = new FormData()
            forms.append('file', data)
            uploadImg(forms).then(res=>{
              this.buttonLoading=false
                if (res.status == 200) {
                  // this.$Message.success(res.message)
                  this.$emit("uploaderSuccess", res.data.filePath)
                  this.cancel()
                } else {
                  this.$Message.error(res.message)
                }
            }).catch(res=>{
              this.buttonLoading=false
              this.$Message.error(res.message)
            })
            // axios.post(
            //   "/bnd-admin/v1/file/uploadImage",
            //   forms,
            //   {
            //     headers: {
            //       'Authorization': 'eyJ2ZXIiOiIxLjAiLCJ0eXAiOiIxIiwiZXB0IjoyLCJraWQiOiJlMDhhYzY2Mi02YWU2LTRiZjktYjlmNS1kYzdmZTMxZTdlMjQiLCJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJVQUFDIiwiaWF0IjoxNTc5MDcyNTk3LCJuYmYiOjE1NzkwNzI1OTcsImF1ZCI6IldFQiIsInN1YiI6Ik5Eb2xSVFlsUWpFbFFVRWxSVFlsUWpRbE9FSXgifQ.AJrhGLNeHj1Csl-3FmkdnaahbLP2QveXkFVfr6GmV3IdFfLBXBK2_G8qn5_ljU_XqWAf5s0Pul1IcgOvzT4WKtuuAOS6bL_GVOEyiVu_oXmqhXxJfUt00FkIeUfEP3IwBEVK9cbYmhrc0a68bnLCEjGUbpj6gocPheZKzAM0XlxXZCob',
            //       'Content-Type': 'multipart/form-data'
            //     }
            //   }
            // ).then(res => {
            //   if (res.data.status == 200) {
            //     console.log(res)
            //     // this.$Message.success("上传成功")
            //     // this.$emit("uploaderSuccess", res.data.data.filePath)
            //     // this.cancel()
            //   } else {
            //     this.$Message.error("上传失败1")
            //   }
            //
            // }).catch(res => {
            //   this.$Message.error("上传失败2")
            // });
          })
        } else {
          // 获取截图的base64 数据
          this.$refs.cropper.getCropData((data) => {
            this.model = true;
            this.modelSrc = data;
          })
        }
      },
      // 实时预览函数
      realTime(data) {
        var previews = data;
        this.previewStyle1 = {
          width: previews.w + "px",
          height: previews.h + "px",
          overflow: "hidden",
          margin: "0",
          transform: `scale(${80 / previews.w})`
        };
        this.previewStyle2 = {
          width: previews.w + "px",
          height: previews.h + "px",
          overflow: "hidden",
          margin: "0",
          transform: `scale(${60 / previews.w})`
        };
        //固定为40宽度
        this.previewStyle3 = {
          width: previews.w + "px",
          height: previews.h + "px",
          overflow: "hidden",
          margin: "0",
          transform: `scale(${40 / previews.w})`
          // zoom: 40 / previews.w
        };
        this.previews = data
      },
      cancel() {
        this.$emit("cnacelModal")
      },
      //选择本地图片
      uploadImg(e, num) {
        console.log('uploadImg',e.target.value);
        var _this = this;
        //上传图片
        var file = e.target.files[0]
        _this.fileName = file.name;
       if (!/\.(jpeg|jpg|png)$/.test(e.target.value)) {
          e.target.value=''
          this.$Message.info("只支持jpg、png、jpeg格式图片!")
          return
        }
        if (file.size / 1024 / 1024 > 2) {
          e.target.value=''
          this.$Message.info("图片不得大于2M!")
          return
        }
        var reader = new FileReader();
        reader.onload = (e) => {
          let data;
          if (typeof e.target.result === 'object') {
            // 把Array Buffer转化为blob 如果是base64不需要
            data = window.URL.createObjectURL(new Blob([e.target.result]))
          } else {
            data = e.target.result
          }
          if (num === 1) {
            _this.option.img = data
          } else if (num === 2) {
            _this.example2.img = data
          }
        }
        // 转化为base64
        // reader.readAsDataURL(file)
        // 转化为blob
        reader.readAsArrayBuffer(file);

      },
      imgLoad(msg) {
        console.log('imgLoad')
        console.log(msg)
      }
    },

  }
</script>

<style scoped lang="less">
  /deep/ .ivu-btn > .ivu-icon {
    width: 14px;
    height: 14px;
    line-height: 1;
  }
  .resetBtn{
    margin-right: 16px;
    background:rgba(240,242,245,1);
    border: 1px solid rgba(240,242,245,1);
    color: #363A40;
  }
  .resetBtn:hover{
    background: #E5E6E8;
  }
  .ic-upload-cloud{
    color:#CDD6E1;
    font-size: 112px;
  }
  /deep/ .cropper-view-box {
    outline: 1px dashed white;
  }

  /deep/ span.cropper-view-box {
    margin-bottom: 16px;
  }

  /deep/ div.cropper-crop-box:after {
    content: '鼠标滚轮缩放图片大小,鼠标拖拽调整图片位置';
    color: white;
    font-size: 12px;
    white-space: nowrap;
    margin-top: 16px;
  }

  /deep/ .crop-info {
    display: none;
  }

  /deep/ .vue-cropper {
    background-image: none;
  }

  .but {
    color: #4183FA;
    border-color: white
  }

  .but:hover {
    background: #3473E7;
    color: white;
  }

  .uploadimg {
    width: 350px;
    height: 350px;
    background: rgba(248, 250, 255, 1);
    opacity: 1;
  }

  .yulanimg {
    margin-left: 2px;
    width: 128px;
    height: 350px;
    background: rgba(248, 250, 255, 1);
    opacity: 1;
  }

  .imgdiv1 {
    width: 80px;
    height: 80px;
    background: #DDDFE8;
    border-radius: 50%;
    border: 2px solid white;
    margin: 21px 0px 0px 25px;
  }

  .imgdiv2 {
    width: 60px;
    height: 60px;
    background: #DDDFE8;
    border-radius: 50%;
    border: 2px solid white;
    margin: 23px 0px 0px 34px;
  }

  .imgdiv3 {
    width: 40px;
    height: 40px;
    background: #DDDFE8;
    border-radius: 50%;
    border: 2px solid white;
    margin: 20px 0px 0px 45px;
  }

  .info {
    width: 720px;
    margin: 0 auto;

    .oper-dv {
      height: 20px;
      text-align: right;
      margin-right: 100px;

      a {
        font-weight: 500;

        &:last-child {
          margin-left: 30px;
        }
      }
    }

    .info-item {
      margin-top: 15px;

      label {
        display: inline-block;
        width: 100px;
        text-align: right;
      }

      .sel-img-dv {
        position: relative;

        .sel-file {
          position: absolute;
          width: 90px;
          height: 30px;
          opacity: 0;
          cursor: pointer;
          z-index: 2;
        }

        .sel-btn {
          position: absolute;
          cursor: pointer;
          z-index: 1;
        }
      }
    }
  }

  .cropper-content {
    display: flex;
    display: -webkit-flex;
    justify-content: flex-end;
    -webkit-justify-content: flex-end;

    .cropper {
      width: 350px;
      height: 350px;
    }

    .show-preview {
      width: 250px;
      height: 250px;
      position: absolute;
      flex: 1;
      -webkit-flex: 1;
      display: flex;
      display: -webkit-flex;
      justify-content: center;
      -webkit-justify-content: center;

      .preview {
        overflow: hidden;
        border-radius: 50%;
        border: 6px solid white;
        background: #DDDFE8;
        margin-left: 40px;
      }
    }
  }

  .cropper-content .show-preview .preview {
    margin-left: 0;
  }

</style>

2.图片上传接口index.js文件

import axios from "axios"

const $postImg = (url, data) => {
  return axios({
    method: 'post',
    url,
    data,
    headers: { 'Content-Type': 'multipart/form-data' }
  })
}

export const uploadImg = (obj) => {
  return $postImg('图片上传路径', obj)
}