Vue中使用vue-croper插件實現圖片上傳裁剪並傳到SpringBoot后台接口


場景

前后端分離的項目,前端修改頭像時,需要對頭像進行裁剪並且能實時預覽,然后上傳到SpringBoot后台。

實現效果如下

 

 

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi
關注公眾號
霸道的程序猿
獲取編程相關電子書、教程推送與免費下載。

實現

插件官網

https://github.com/xyxiao001/vue-cropper

安裝插件

npm install vue-cropper

引用插件

組件內使用
import { VueCropper }  from 'vue-cropper' 
components: {
  VueCropper,
},

main.js里面使用
import VueCropper from 'vue-cropper'

Vue.use(VueCropper)

cdn方式使用
<script src="//cdn.jsdelivr.net/npm/vue-cropper@0.4.9/dist/index.js"></script>
Vue.use(window['vue-cropper'].default)
nuxt 使用方式
if(process.browser) {
  vueCropper = require('vue-cropper')
  Vue.use(vueCropper.default)
}

這里只是在頭像上傳組件內使用,所以采用

import { VueCropper }  from 'vue-cropper' 
components: {
  VueCropper,
},

的方式。

使用

把上傳圖片和裁剪圖片和預覽都放在一個dialog里面,只有在點擊修改頭像按鈕時才顯示此dialog

    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened">
      <el-row>
        <el-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"
            v-if="visible"
          />
        </el-col>
        <el-col :xs="24" :md="12" :style="{height: '350px'}">
          <div class="avatar-upload-preview">
            <img :src="previews.url" :style="previews.img" />
          </div>
        </el-col>
      </el-row>
      <br />
      <el-row>
        <el-col :lg="2" :md="2">
          <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
            <el-button size="small">
              上傳
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>
          </el-upload>
        </el-col>
        <el-col :lg="{span: 1, offset: 2}" :md="2">
          <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
        </el-col>
        <el-col :lg="{span: 1, offset: 1}" :md="2">
          <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
        </el-col>
        <el-col :lg="{span: 1, offset: 1}" :md="2">
          <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
        </el-col>
        <el-col :lg="{span: 1, offset: 1}" :md="2">
          <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
        </el-col>
        <el-col :lg="{span: 2, offset: 6}" :md="2">
          <el-button type="primary" size="small" @click="uploadImg()">提 交</el-button>
        </el-col>
      </el-row>
    </el-dialog>

這個dialog的布局的效果如下

 

 

通過:visible.sync="open" 綁定的是否顯示的變量為open,需要聲明

    data() {
      return {
        // 是否顯示彈出層
        open: false,

然后在修改頭像按鈕的點擊事件中

      // 編輯頭像
      editCropper() {
        this.open = true;
      },

顯示此dialog

然后圖片裁剪控件的代碼為

          <vue-cropper
            ref="cropper"
            :img="options.img"
            :info="true"
            :autoCrop="options.autoCrop"
            :autoCropWidth="options.autoCropWidth"
            :autoCropHeight="options.autoCropHeight"
            :fixedBox="options.fixedBox"
            @realTime="realTime"
            v-if="visible"
          />

此控件的屬性

 

名稱 功能 默認值 可選值
img 裁剪圖片的地址 url 地址 || base64 || blob
裁剪生成圖片的質量 1 0.1 - 1
outputType 裁剪生成圖片的格式 jpg (jpg 需要傳入jpeg) jpeg || png || webp
裁剪框的大小信息 true true || false
canScale 圖片是否允許滾輪縮放 true true || false
是否默認生成截圖框 false true || false
autoCropWidth 默認生成截圖框寬度 容器的80% 0~max
默認生成截圖框高度 容器的80% 0~max
fixed 是否開啟截圖框寬高固定比例 true true | false
截圖框的寬高比例 [1, 1] [寬度, 高度]
full 是否輸出原圖比例的截圖 false true | false
固定截圖框大小 不允許改變 false true | false
canMove 上傳圖片是否可以移動 true true | false
截圖框能否拖動 true true | false
original 上傳圖片按照原始比例渲染 false true | false
截圖框是否被限制在圖片里面 false true | false
high 是否按照設備的dpr 輸出等比例圖片 true true | false
true 為展示真實輸出圖片寬高 false 展示看到的截圖框寬高 false true | false
maxImgSize 限制圖片最大寬度和高度 2000 0-max
圖片根據截圖框輸出比例倍數 1 0-max(建議不要太大不然會卡死的呢)
mode 圖片默認渲染方式 contain contain , cover, 100px, 100% auto

這里設置此插件的一些屬性與對象options的屬性綁定。

聲明對象options並設置一些屬性

        options: {
          img: 'https://images.cnblogs.com/cnblogs_com/badaoliumangqizhi/1539113/o_qrcode_for_gh_f76a8d7271eb_258.jpg', //裁剪圖片的地址
          autoCrop: true, // 是否默認生成截圖框
          autoCropWidth: 200, // 默認生成截圖框寬度
          autoCropHeight: 200, // 默認生成截圖框高度
          fixedBox: true // 固定截圖框大小 不允許改變
        },

 

這里給裁剪的圖片設置了一張默認圖片,在上傳后會重新給該img屬性賦值,img就是裁剪圖片的地址。

實時預覽是通過 @realTime="realTime"

綁定的函數realTime

      // 實時預覽
      realTime(data) {
        this.previews = data;
      }

 

會將參數data賦值給定義的對象preview

previews: {}

 

然后上面的布局中預覽的img是

        <el-col :xs="24" :md="12" :style="{height: '350px'}">
          <div class="avatar-upload-preview">
            <img :src="previews.url" :style="previews.img" />
          </div>
        </el-col>

 

給img標簽賦值參數的url style賦值img屬性就可。可以參照其官方案例

@realTime="realTime"
// Real time preview function
realTime(data) {
  var previews = data;
  var h = 0.5;
  var w = 0.2;

  this.previewStyle1 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: h
  };

  this.previewStyle2 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: w
  };

  固定為100寬度
  this.previewStyle3 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: 100 / preview.w
  };

  固定為100高度
  this.previewStyle4 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: 100 / preview.h
  };
  this.previews = data;
},


<div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px',  'overflow': 'hidden',
    'margin': '5px'}">
  <div :style="previews.div">
    <img :src="option.img" :style="previews.img">
  </div>
</div>
<p>中等大小</p>
<div :style="previewStyle1"> 
  <div :style="previews.div">
    <img :src="previews.url" :style="previews.img">
  </div>
</div>

<p>迷你大小</p>
<div :style="previewStyle2"> 
  <div :style="previews.div">
    <img :src="previews.url" :style="previews.img">
  </div>
</div>

 

下方那一排的圖片的縮放和旋轉都是調用的插件自帶的函數

     // 向左旋轉
      rotateLeft() {
        this.$refs.cropper.rotateLeft();
      },
      // 向右旋轉
      rotateRight() {
        this.$refs.cropper.rotateRight();
      },
      // 圖片縮放
      changeScale(num) {
        num = num || 1;
        this.$refs.cropper.changeScale(num);
      },

 

此插件的其他內置函數

this.$refs.cropper.startCrop() 開始截圖
this.$refs.cropper.stopCrop() 停止截圖
this.$refs.cropper.clearCrop() 清除截圖
this.$refs.cropper.changeScale() 修改圖片大小 正數為變大 負數變小
this.$refs.cropper.getImgAxis() 獲取圖片基於容器的坐標點
this.$refs.cropper.getCropAxis() 獲取截圖框基於容器的坐標點
this.$refs.cropper.goAutoCrop 自動生成截圖框函數
this.$refs.cropper.rotateRight() 向右邊旋轉90度
this.$refs.cropper.rotateLeft() 向左邊旋轉90度
圖片加載的回調 imgLoad 返回結果success, error
獲取截圖信息
this.$refs.cropper.cropW 截圖框寬度

this.$refs.cropper.cropH 截圖框高度

// 獲取截圖的base64 數據
this.$refs.cropper.getCropData((data) => {
  // do something
  console.log(data)  
})

// 獲取截圖的blob數據
this.$refs.cropper.getCropBlob((data) => {
  // do something
  console.log(data)  
})

 

前端上傳圖片的實現是使用ElementUI的el-upload實現。

        <el-col :lg="2" :md="2">
          <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
            <el-button size="small">
              上傳
              <i class="el-icon-upload el-icon--right"></i>
            </el-button>
          </el-upload>

 

這里要對其進行一些設置

將其action設置為#不讓其上傳到遠程url,然后重寫覆蓋其http-request

      // 覆蓋默認的上傳行為
      requestUpload() {
      },

 

來覆蓋其默認的上傳行為。

然后重寫其上傳前的方法進行上傳預處理

      // 上傳預處理
      beforeUpload(file) {
        if (file.type.indexOf("image/") == -1) {
          this.msgError("文件格式錯誤,請上傳圖片類型,如:JPG,PNG后綴的文件。");
        } else {
          const reader = new FileReader();
          reader.readAsDataURL(file);
          reader.onload = () => {
            this.options.img = reader.result;
          };
        }
      },

 

在方法中判斷上傳文件的類型是否是圖片,然后獲取圖片的url並將其賦值給option的img屬性,這樣裁剪控件就能獲取到上傳的圖片的url並能顯示。

而實時預覽也能通過裁剪控件的data的url獲取到。

然后就是點擊提交按鈕裁剪后的照片提交給SpringBoot后台

 

     // 上傳圖片
      uploadImg() {
        this.$refs.cropper.getCropBlob(data => {
          let formData = new FormData();
          formData.append("file", data);
          uploadimg(formData).then(response => {
            if (response.code === 200) {
              this.open = false;
              this.options.img = process.env.VUE_APP_BASE_API + response.data;
              console.log(this.options.img)
              this.$emit('changezp', this.options.img)
              this.msgSuccess("修改成功");
            }
            this.visible = false;
          });
        });
      },

 

通過this.$refs.cropper以及設置的ref="cropper"來獲取裁剪控件,然后調用他的內置函數獲取blob數據。

然后構建一個FormData對象,並設置其file為裁剪圖片的data

然后將此formData采用post請求的方式提交到SpringBoot后台

// 用戶頭像上傳
export function uploadAvatar(data) {
  return request({
    url: '/system/user/profile/avatar',
    method: 'post',
    data: data
  })
}

 

這里的request是封裝的axios請求對象向后台發動post請求並傳遞data參數。

在SpringBoot后台

    @PostMapping("/upload")
    public AjaxResult uploadProfile(MultipartFile file){
        try {
            String path = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
            path = path.replaceAll("//","/");
            System.out.println("========path: " + path);
            return AjaxResult.success("success",path);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("上傳失敗");
        }

    }

 

就能通過MultipartFile file接受到圖片文件並上傳到服務器返回前端能訪問靜態資源的路徑。

具體實現可以參照下面博客

https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108383134


免責聲明!

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



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