前端圖片裁剪實戰

  • 蘇格團隊
  • 做者:Bigben

在當下的的前端項目中,圖片功能能夠說是很是常見的,圖片的展現、圖片的裁剪編輯、圖片的上傳等,那麼咱們的項目便來了個需求。css

當下咱們項目中須要一個可自由編輯圖片的功能,當圖片可能出現須要頻繁編輯,同時能知足發現裁剪不滿意想要微調的時候,會發現若是咱們處理圖片按照日常的習慣,如裁剪後上傳服務器或者轉base64,都是不符合需求的。那麼該怎麼處理比較好呢?如何以儘可能少的網絡請求、少佔用存儲來解決應用場景呢?那麼,便想到了只用純數據來跟咱們的功能打交道。前端

先安利個裁圖神器cropperjs,我的認爲是個易上手,配置和api方法蠻齊全的一個組件庫。react

項目內引入,必定不要漏了引用樣式git

import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
複製代碼

這裏咱們以react爲例github

this.state = {
  width: 640,   //圖片展現寬
  height: 360,   //圖片展現高   
  imgWidth: 640,   //圖片實際寬
  imgHeight: 360,   //圖片實際高
  imgLeft: 0,   //圖片左偏移
  imgTop: 0,   //圖片上偏移
  editing: false   //是否編輯中
}
//展現圖片的基本dom結構,咱們使用外div內img的形式,來跟數據結合控制裁剪圖片的展現
const { width, height, imgWidth, imgHeight, imgLeft, imgTop, editing } = this.state;
const containerStyle = {
  width: `${width}px`,
  height: `${height}px`
}
const imgStyle = {
  width: `${imgWidth}px`,
  height: `${imgHeight}px`,
  left: `${imgLeft}px`,
  top: `${imgTop}px`
}

.img-container {
  overflow: hidden;
  position: relative;
}

.crop-img {
  position: absolute;
  left: 0;
  top: 0;
}
<div 
  className="img-container" 
  style={containerStyle}
>
  <img 
    className="crop-img"
    src={picture} 
    style={imgStyle} 
    alt="pic"
  ></img>
</div>
複製代碼

簡單來講就是外層元素控制裁剪展現的寬高,同時根據項目需求的元素定位也掛在這,內部img掛載圖片實際大小和偏移。canvas

cropperjs初始化後的元素,是會與初始化對象img處在同一dom層級,也就是說若是咱們直接對展現img進行初始化的話,編輯區域展現將會受父元素,如圖,放大圖片時候會不方查看超出部分 api

因此在這裏,爲了圖片編輯的自由度,建議分開展現dom與用以初始化cropper對象的dom,在這裏編輯區域爲全屏幕爲例,根據項目實際功能區域進行調整bash

.edit-container {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}

<div 
  className="img-container" 
  style={containerStyle}
>
  <img 
    className="crop-img"
    src={picture} 
    style={imgStyle} 
    alt="pic"
  ></img>
</div>

//cropper初始化
this.myRef = React.createRef();
this.myCropper = new Cropper(this.myRef.current, options);
//options配置
const options = {
    dragMode: 'move',   //使裁剪時圖片可拖動
    background: false,  //由於咱們如今是全屏可編輯,須要隱藏掉默認的背景
}
//固然還有許多常見的配置項,如編輯框尺寸比例等,你們可自行查看api

//裁剪保存
save() {
const cropBoxData = this.myCropper.getCropBoxData();    //獲取裁剪框數據
const canvasData = this.myCropper.getCanvasData();      //獲取圖片數據
this.setState({
  width: cropBoxData.width,
  height: cropBoxData.height,
  imgLeft: canvasData.left - cropBoxData.left,
  imgTop: canvasData.top - cropBoxData.top,
  imgWidth: canvasData.width,
  imgHeight: canvasData.height
})
}
複製代碼

這樣的話 咱們就能夠徹底在自定義的全屏內編輯,保存效果以下,到這裏咱們就完成了第一部分功能,裁剪並保存數據和展現服務器

重點介紹下咱們用到的兩個api方法getCropBoxData和getCanvasData,getCanvasData是用來獲取圖片的實際數據的(當前的寬高,和相對於父元素可視區域的位移偏移量),getCropBoxData則是獲取相對於圖片區域的裁剪區相關數據。網絡

那麼後續的需求接着來了,咱們怎麼作到二次編輯的時候,能還原效果呢,嗯,其實在前面咱們記錄裁圖數據的時候,把相應的數據關係再計算一遍就行了,在初始化cropper的options中增長配置

const options = {
dragMode: 'move',
background: false,
//控件初始化後重置相應配置
ready: () => {
  const { width, height, imgWidth, imgHeight, imgLeft, imgTop } = this.state;
  //根據實際須要出現裁圖功能進行定位,此處left和top僅爲測試暫時默認值定義
  const left = 50;  
  const top = 50;
  this.myCropper.setCanvasData({
    width: imgWidth,
    height: imgHeight,
    left: left,
    top: top
  });
  this.myCropper.setCropBoxData({
    left: left - imgLeft,
    top: top - imgTop,
    width: width,
    height: height
  })
  
}
}
this.myCropper = new Cropper(this.myRef.current, options);
複製代碼

這時候咱們再點擊裁圖,就完美還原了,左邊和上邊的間隙就是setCanvasData的top和left,根據實際項目進行調整,setCropBoxData的left和top是相對於cropper-canvas的定位,纔有了以上的計算形式。

此時,基本功能到此結束,若是說是應用在h5編輯中,設計到scale縮放的話,相關的數據計算都要算上scale的縮放值哦,否則就會出現展現圖片和編輯圖片大小不對等的情況。同時還有許多功能就不作展現了,設置裁剪框比例,編輯縮放等,歡迎嘗試。

固然了,若是想要保存圖片,也有相應的方法處處裁剪圖片的數據

this.myCropper.getCroppedCanvas().toDataURL('image/jpeg')
複製代碼

最後,咱們能夠看到,在整個功能過程當中,咱們須要的只是裁剪的數據,讀寫快,也不須要進行額外的圖片存儲,減小文件服務器存儲的開銷與優化。

cropperjs github:github.com/fengyuanche…

感謝你們收看,歡迎討論和指正。

相關文章
相關標籤/搜索