10.vue+elementUI+vue-cropper圖片裁剪並上傳


最終達到這樣的效果:

以下省略了一些簡單的代碼,比如組件引入等

1、引入element ui上傳組件

 <upload-img :pic="form.bgImage" @getUrlFn="getImgUrl" @modalShowFn="getModalStatus"></upload-img>

2、uploadImg組件內容

<template>
  <div>
    <!-- accept="image/gif, image/jpeg,image/jpg,image/png,image/bmp" -->
    <el-upload
      class="avatar-uploader"
      v-loading="loading"
      :action="action"
      :data="uploadData"
      :show-file-list="false"
      name="file"
      :on-success="handleAvatarSuccess"
      :on-progress="handProcess"
      :http-request="picUpload"
      :before-upload="beforeAvatarUpload"
    >
      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
    <div v-if="maskBox" @mouseleave="maskBox = false" class="mask">
      <i @click="handleRemove" style="font-size: 24px" class="el-icon-delete"></i>
    </div>
  </div>
</template>
<script>
export default {
  props: {
    pic: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      action: '上傳地址',
      disabled: false,
      uploadData: {
        file: '',
        project: ''
      },
      imageUrl: '',
      loading: false,
      maskBox:false,
    }
  },
  watch: {
    pic: {
      handler(newval, oldval) {
        console.log(newval)
        if (newval) {
          this.imageUrl = newval
        }
      },
      deep: true
    }
  },
  created() {
    this.imageUrl = this.picUrl
  },
  methods: {
    // 圖片上傳前觸發裁剪組件
    // 將圖片讀出並在完成時觸發裁剪
    picUpload(option) {
      let file = option.file
      let reader = new FileReader();
      if (file) {
        reader.readAsDataURL(file)
      }
     reader.onload = () => {
        let src = reader.result
        // this.cropperShow = true
        // this.cropperImg = src
        let obj = {
          cropperShow:true,
          cropperImg:src
        }
        this.$emit("modalShowFn",obj)
      }
    },
    handleRemove(file) {
      this.imageUrl = '';
      this.maskBox = false;
      this.$emit('getUrlFn', '')
    },
    handleAvatarSuccess(res, file) {
      this.imageUrl = res.browser;
      this.loading = false;
      this.$emit('getUrlFn', res.browser, file.raw)

    },
    beforeAvatarUpload(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>

3、安裝vue-cropper,在頁面中引入vue-cropper

npm install vue-cropper --save
import vueCropper from "vue-cropper"

4、用vue-cropper封裝圖片裁剪組件

組件放入modal中

 <Modal v-model="isShowCropper" class="cropperModal" :closable="false" width="530px">
      <div class="cropperModalBody" style="width:520px;height:350px">
        <img-cropper
          :cropperOption="cropperOption"
          :img="cropperImg"
          :file="cropperFile"
          @cropperFinish="postUploadFile"
          @close="()=>{isShowCropper=false}"
        ></img-cropper>
      </div>
      <div slot="footer"></div>
    </Modal>

一些方法

 getImgUrl(url) {
      this.form.bgImage = url
    },
    getModalStatus(obj) {
      this.cropperImg = obj.cropperImg;
      this.isShowCropper = obj.cropperShow;
    },

    // 文件上傳-接口-上傳文件
    postUploadFile(blob) {
      //將blob轉換為file
      let file = new File([blob], '圖片.png', { type: 'image/png', lastModified: Date.now() });
      file.uid = Date.now();
      var fd = new FormData();
      fd.append("file", file, "圖片.png");
      fd.append("project", "micropark_coordination");

      uploadFile(fd).then(res => {
        if (res.code === 200) {
          this.form.bgImage = res.browser;
          //  this.$refs.upload.clearFiles()
          this.isShowCropper = false;
          this.cropperImg = null;
          this.cropperFile = {};
        }
      });
    }

5、img-cropper組件內容

<template>
  <div class="vue-cropper-box">
    <div class="vue-cropper-header">
      <p class="title" style="font-size:16px">
        圖片裁剪
        <Icon type="ios-close" @click="close()" />
      </p>
    </div>
    <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">確定裁剪</button>
    </div>
    <div class="vue-cropper-content" style="width:500px;height:310px">
      <vueCropper
        ref="cropper"
        :img="img"
        :outputSize="cropperOption.outputSize"
        :outputType="cropperOption.outputType"
        :info="cropperOption.info"
        :full="cropperOption.full"
        :canMove="cropperOption.canMoveBox"
        :canMoveBox="cropperOption.canMoveBox"
        :original="cropperOption.original"
        :canScale="cropperOption.canScale"
        :autoCrop="true"
        :autoCropWidth="200"
        :autoCropHeight="200"
        :fixedBox="true"
        :fixed="cropperOption.fixed"
        :fixedNumber="cropperOption.fixedNumber"
        :centerBox="cropperOption.centerBox"
        :infoTrue="cropperOption.infoTrue"
        @realTime="realTime"
        @imgLoad="imgLoad"
      ></vueCropper>
    </div>
  </div>
</template>
<script>
import vueCropper from "vue-cropper"
export default {
  name: 'by-cropper',
  components: { vueCropper },
  // inject: ['reload'],
  filters: {},
  props: {
    file: {
      default: () => { },
      required: true
    },
    img: {
      default: "",
      required: true
    },
    cropperOption: {
      default: () => ({
        // img: '', // 裁剪圖片的地址
        info: true, // 裁剪框的大小信息
        outputSize: 1, // 裁剪生成圖片的質量
        full: false, // 輸出原圖比例截圖 props名full
        outputType: 'png', // 裁剪生成圖片的格式
        canMove: true, // 能否拖動圖片
        original: false, // 上傳圖片是否顯示原始寬高
        canMoveBox: true, // 能否拖動截圖框
        canScale: false, // 圖片是否允許滾輪縮放
        autoCrop: true, // 是否默認生成截圖框
        autoCropWidth: 200, // 默認生成截圖框寬度
        autoCropHeight: 200, // 默認生成截圖框高度
        fixedBox: true, // 截圖框固定大小
        fixed: true, // 是否開啟截圖框寬高固定比例
        fixedNumber: [1, 1], // 截圖框的寬高比例
        original: false, // 上傳圖片按照原始比例渲染
        centerBox: true, // 截圖框是否被限制在圖片里面
        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) => {
          let file = data;
          file.name = this.file.name;
          this.$emit('cropperFinish', file, data);
        });

      } else {
        this.$refs.cropper.getCropData(data => {

          // 將剪裁后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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM