1. 程式人生 > 實用技巧 >在vue中使用vue-cropper圖片裁剪並上傳圖片(配合ant-design-vue的upload元件)

在vue中使用vue-cropper圖片裁剪並上傳圖片(配合ant-design-vue的upload元件)

在vue中使用vue-cropper圖片裁剪並上傳圖片

思路:封裝一個對話方塊(Modal),裡面包含一個vue-cropper,用於ant-upload上傳檔案時呼叫彈出此對話方塊讓使用者編輯此圖片.裁剪完emit一個事件,然後上傳這個編輯後的圖片(file)

先是對vue-cropper進行再封裝

該元件就對外''暴露 "2個操作 1. 傳入影象資料並開啟對話方塊 2. 影象處理完後返回影象資料 這使用起來方便

碼來:src\components\common\cropper-modal.vue

<template>
  <a-modal
    :visible="visible"
    title="請裁剪圖片"
    :maskClosable="false"
    :confirmLoading="confirmLoading"
    @cancel="handleCancel"
    @ok="handleOk"
  >
    <div class="cropper-wrapper">
      <vue-cropper
        ref="cropper"
        :img="img"
        :info="true"
        :original="true"
        :autoCrop="options.autoCrop"
        :autoCropWidth="options.autoCropWidth"
        :autoCropHeight="options.autoCropHeight"
        :fixedBox="options.fixedBox"
      ></vue-cropper>
    </div>
  </a-modal>
</template>

<script>
import { VueCropper } from 'vue-cropper'
export default {
  components: {
    VueCropper,
  },
  data() {
    return {
      // ant-modal相關配置
      visible: false,
      confirmLoading: false,
      // vue-cropper相關配置 詳細的可以去github上看文件
      img: null, //要裁剪的影象資源 可選項: url地址 || base64 || blob
      options: {
        autoCrop: true, //是否預設生成截圖框
        autoCropWidth: 200, //預設生成截圖框寬度
        autoCropHeight: 200, //預設生成截圖框高度
        fixedBox: true, //固定截圖框大小 不允許改變
      },
    }
  },
  methods: {
    // 呼叫此方法需傳入一個 [url地址 || base64 || blob]
    // 父元件呼叫: this.$refs['cropperModal'].edit(引數)
    edit(image) {
      this.img = image
      this.visible = true
    },
    // 監聽對話方塊的OK/Cancel按鈕的點選事件
    handleOk() {
      const that = this
      that.confirmLoading = true
      // 獲取截圖的base64 資料
      // getCropBlob獲取二進位制資料
      this.$refs.cropper.getCropData((data) => {
        //將裁剪侯後的圖片物件射給**父元件**,然後關閉對話方塊
        that.$emit('ok', data)
        that.handleCancel()
      })
    },
    handleCancel(e) {
      this.visible = false
    },
  },
}
</script>

<style lang="scss" scoped>
.cropper-wrapper {
  width: 100%;
  height: 400px;
}
</style>

父元件是用了ant-design-vue的upload元件

關鍵程式碼如下:顯示為一個按鈕,點選更換頭像後彈出檔案選擇框,再選擇檔案後先是呼叫beforeUpload判斷檔案型別,滿足條件然後呼叫

handleUploadChange函式

@ok="handleOK"就是在圖片裁剪後 emit的ok事件

        <a-upload
          :before-upload="beforeUpload"
          :show-upload-list="false"
          :custom-request="function(){}"
          @change="handleUploadChange"
        >
          <a-button type="primary">更換頭像</a-button>
        </a-upload>

<cropper-modal @ok="handleOK" ref="cropperModal" />
	// 在父元件的methods中   

	// 選擇檔案後且beforeUpload返回為true後會呼叫這個方法
    handleUploadChange(info) {
      // 這個回撥函式的引數是個File物件,所以要用FileReader將物件轉換成 data-uri (base64) 物件,才能給vue-cropper
      var reader = new FileReader()
      const _this = this
      // 當檔案處理完成的回撥函式
      reader.onload = function (e) {
        // e.target.result 該屬性表示目標物件的DataURL
        // 然後呼叫cropperModal的edit方法使得對話方塊可見
        _this.$refs['cropperModal'].edit(e.target.result)
      }
     // 記錄原始的檔名字,用於DataURL(base64)轉成file物件,不轉就可以不用
      this.tmpImgName = info.file.name
     // 檔案處理 file=>base64 
      reader.readAsDataURL(info.file.originFileObj)
    },
	
    // 對檔案格式校驗(ant-upload選擇檔案框是所有型別的)   
    beforeUpload(file) {
        var fileType = file.type
        console.log(file.type)
        if (fileType.indexOf('image') < 0) {
            this.$message.warning('請上傳圖片')
            return false
        }
    },
        
 // 然後這裡可以呼叫api請求上傳圖片
  handleOK(data) {
      console.log(data)
      let file = this.dataURLtoFile(data, this.tmpImgName)
      console.log(file)
	 // ....省略api請求 2種格式的物件都拿到了 怎麼請求不用說了吧
    },
        
// 將base64轉換為檔案 百度隨便找的 看需求使用
    dataURLtoFile(dataurl, filename) {
      var arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], filename, { type: mime })
    },
        

附帶一個axios上傳multipart格式的檔案方法

  // 上傳頭像 File型別
  uploadAvatar(file) {
    let param = new FormData()  // 建立form物件
    param.append('file', file)  // 通過append向form物件新增資料
    // param.append('chunk', '0') // 新增form表單中其他資料
    let config = {
      headers: { 'Content-Type': 'multipart/form-data' }
    }
    return axios.post('/upload/avatar', param, config)
  },

參考連結

文件教程:http://github.xyxiao.cn/vue-cropper/example/

他人教程:https://www.jianshu.com/p/4024cf503380

結合antv:https://blog.csdn.net/qq_36111804/article/details/94599536

HTML5 file物件和blob物件的互相轉換 https://www.jianshu.com/p/5b44c41adfe2