基于 vue-cropper 的簡單圖片裁剪插件實現(xiàn)

起由

最近在工作中遇到了在 VUE 下需要簡單裁剪圖片的需求,同時還要對圖片進行相關大小和格式的限制

這個時候就想起了在 jq 時代大名鼎鼎的 cropper.js 了

簡單的界面設計如下圖:

效果圖

分析

從圖中可以看出,我們需要的功能主要有如下幾方面的內(nèi)容:

  • 獲取到圖片資源
  • 一個帶模板的彈出層
  • 截圖組件
  • 交互區(qū)域(這里指圖中的確定取消按鈕)
  • 足夠的可擴展性

實現(xiàn)思路

首先需要完成的當然是獲取到用戶上傳的文件,第一個想法是使用原生的方案,也即使用原生的 input 框進行相關事件的獲取

<input type="file" />

這樣的方式擴展是最靈活的,但是同時也是最繁瑣的,事無巨細都需要一一考慮,這不符合我們敏捷開發(fā)的原則

考慮到項目中已引入 elementui 的環(huán)境,故考慮使用 \color{#409eff}{element}中的 \color{#409eff}{Upload} 組件來進行獲取文件的操作

項目需求決定只能操作單張圖片,進行相關配置后效果圖如下:

觸發(fā)選擇框

獲取到了文件之后首先需要對于 文件類型大小 進行校驗,確定其為我們真實希望獲得的類型和滿足我們對于圖片的大小限制

接著我們需要將獲取到的圖片傳遞給截圖組件,且在用戶按下確認或取消時能 立即響應, 完成獲取截圖的文件和截圖等過程,最后將新截的圖片加進預覽并保存新的圖片狀態(tài)

以上便是我們在這個組件中整個想要完成的功能流程

Show me the code

其實在同樣的思路下,會有千萬種實現(xiàn)方法,以下僅是我個人對于這一想法的一些實踐,歡迎討論指正

首先是有 \color{#409eff}{Upload}標簽(此處隱去引入庫及掛載過程)

          <el-upload
            :before-upload="beforeUpload"      //  上傳前的事件,在這里做文件類型和大小的檢查
            :file-list="showImgUrl"            //   圖片預覽列表
            :http-request="picUpload"          //  上傳事件,覆蓋默認上傳事件,應在此處將圖片傳入截圖組件
            :limit="1"                         //  文件數(shù)量限制
            :multiple="false"                  //  選擇文件時不允許選擇多文件
            :on-exceed="overFile"              //  文件數(shù)量超出限制時的鉤子函數(shù),應在此處做覆蓋以及提示
            :on-remove="removeFile"            //  圖片刪除時的鉤子函數(shù),應在此時清空圖片的緩存相關操作 
            action                             //  默認跳轉(zhuǎn)地址,這里設置為空
            list-type="picture-card"           //  文件選擇框的樣式以及插入動畫
            ref="upload"                       //  DOM 鉤子
          >
          <i class="el-icon-plus"></i>         //  樣式需要的圖標
          </el-upload>

我們整個流程都可以從 \color{#409eff}{Upload} 標簽的生命周期處體現(xiàn)

接著我們來一個一個看看在這些鉤子函數(shù)里我們都做了什么吧:

    // 圖片上傳前校驗
   //  這里對圖片類型和大小做出限制 
    beforeUpload(file) {
      const isLt5M = file.size < 5 * 1024 * 1024
      const fileType = file.type.split('/')[0]
      if (!isLt5M) {
        this.$message.error('圖片大小不能超過5M')
        return false
      }
      if (fileType !== 'image') {
        this.$message.error('只能上傳圖片格式')
        return false
      }
    },

圖片校驗通過后即進入裁剪流程,我們是通過覆蓋默認上傳事件實現(xiàn)的

在這里由于從本地讀出時沒有相關的 url 信息,所以我們在這里使用 fileReader API 把獲取到的圖片文件轉(zhuǎn)化成 base64 的格式,然后再進行相關的操作

  //  在生命周期掛載完成的時候判斷瀏覽器中是否為現(xiàn)代瀏覽器
  //  若不支持 FileReader API 則提示并退出編輯操作
  mounted() {
    if (!window.FileReader) {
      this.$alert('您的瀏覽器版本過舊,請更換現(xiàn)代瀏覽器進行操作', '提示').then(
        () => {
          this.__cancel()
        }
      )
    }
  },
    // 圖片上傳前觸發(fā)裁剪組件
    // 將圖片讀出并在完成時觸發(fā)裁剪 
    picUpload(option) {
      let file = option.file
      if (file) {
        this.fileReader.readAsDataURL(file)
      }
      this.fileReader.onload = () => {
        let src = this.fileReader.result
        this.cropperShow = true
        this.cropperImg = src
      }
    },

這里應該調(diào)起裁剪插件,猛地發(fā)現(xiàn),插件我都還沒新增鴨

可怕!!

于是就回去翻了翻 cropperjs 的文檔,emmmm, 真的沒有意外,還是 jq 時代的樣子,沒有辦法直接拿下來就用,那么這個輪子究竟有沒有人已經(jīng)造過了呢,目光下移, vue-cropper 進入了我的視線

(這里忽略下載引入的過程,直接從使用開始)

    //  圖片裁剪引用
    //  el-dialog 為 element 中彈框組件
    //  cropperShow: 是否顯示  load: 用戶是否處于交互狀態(tài)  cropperImg: 圖片源 
    //  更多配置項請參考 vue-cropper 相關文檔
    <el-dialog :visible.sync="cropperShow" width="640px" :close-on-click-modal="false" :show-close="false">
      <span slot="title">操作圖片</span>        // 標題文字
      <vueCropper
        ref="cropper"                          // Dom鉤子,用于獲取綁定其上的相關屬性及函數(shù)
        class="cropper"
        :img="cropperImg"                      // 裁剪圖片源
        :can-scale="!load"                     // 是否允許滾輪縮放
        :auto-crop="true"                      // 是否默認生成截圖框
        :fixed-box="true"                      // 是否固定截圖框大小
        enlarge="2"                            // 輸出比例倍數(shù) 
        :output-size="option.size"             // 生成圖片質(zhì)量
        :output-type="option.outputType"       // 生成圖片格式
        :center-box="option.centerBox"         // 截圖框是否限制在圖片內(nèi)
        :fixed-number="[1,1]"                  // 截圖框的寬高比例
      ></vueCropper>
      <div class="cropper-btn">
        <el-button type="primary" @click="confirm" :loading="load">確定</el-button>
        <el-button @click="cancel" :disabled="load">取消</el-button>
      </div>
      <el-dialog                                // 用戶交互中彈出的提示彈框
        width="30%"
        :visible.sync="load"
        append-to-body
      >
        <div slot="title">飛速處理圖片中...</div>
      </el-dialog>
    </el-dialog>
     //  配置參數(shù)
      option: {
        size: 0,
        outputType: '',
        centerBox: false
      },

此時我們就能看到文章開頭所呈現(xiàn)的相關效果了,并且我們也能通過插件提供的鉤子函數(shù)獲取到相應的圖片數(shù)據(jù)

但是我們想要走完整個流程,還必須添加交互響應事件以及進行相關的上傳操作

    // 確定選擇
    // dom.getCropData() 獲取當前截圖框圖像的 base64 格式的數(shù)據(jù)
    // 獲取成功數(shù)據(jù)后調(diào)起上傳操作
    confirm() {
      this.$refs.cropper.getCropData(data => {
        this.httpRequest(data)
        this.load = true
      })
    },
    // 取消
    cancel() {
      console.log('cancel edit picture')
      // 關閉裁剪組件相關操作
    }
    // 圖片裁剪后上傳
    // 這里可進行進一步優(yōu)化將 config 請求配置寫入 http 請求庫中
    httpRequest(src) {
      let config = {
        url: '***',             // 這里填后端的圖片上傳鏈接
        method: 'post',
        data: {
          //  截取 base64 文件部分
          image: src.split(',')[1]
        }
      }
      this.$ehttp
        .postUpload(config)
        .then(res => {
          console.log(res, '*********************************************')
          if (res.data.code === 0) {
            this.params.properties.imageHash = res.data.data
            this.$message.success('圖片編輯成功')
            this.$refs.upload.clearFiles()                              //  清空預覽列表
            this.showImgUrl = [{ name: 'pic', url: src }]               // 將新上傳圖片插入上傳列表  
            this.cropperShow = false
          } else {
            // this.$message.error('res.dat')
            this.$refs.upload.clearFiles()
          }
        })
        .catch(err => {
          this.$message.error(err)
        })
    },

結(jié)語

至此我們整個裁剪插件就已經(jīng)全部完成了,通過上傳回參可以任意處理裁剪后的圖像了

整個流程下來主要的感覺是對于圖片格式的轉(zhuǎn)換會相對的比較繁瑣

vue-cropper 插件本身只完成裁剪的功能,方便我們在此基礎上開發(fā)個性化的裁剪插件

同時由于其基于 cropperjs 開發(fā),所以在截圖框的樣式方面由插件寫死了,若是我們對于截圖框的樣式也有個性化需求則可 down 下源碼進行自定義修改,這已經(jīng)超出了本文的范圍故會在后面的文章中進行相關的研究(坑先挖好,填不填就看心情了hhh)


傲嬌.jpg

參考資料

ElementUI: https://element.eleme.cn/#/zh-CN/component/upload
CropperJS: https://github.com/fengyuanchen/cropper
vue-cropper: https://github.com/xyxiao001/vue-cropper

PS

最后當然是日常求贊環(huán)節(jié)啦~

Clancy
2019.5.30

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容