javascript實(shí)現(xiàn)自由編輯圖片代碼詳解
當(dāng)下我們項(xiàng)目中需要一個(gè)可自由編輯圖片的功能,當(dāng)圖片可能出現(xiàn)需要頻繁編輯,同時(shí)能滿足發(fā)現(xiàn)裁剪不滿意想要微調(diào)的時(shí)候,會(huì)發(fā)現(xiàn)如果我們處理圖片按照平常的習(xí)慣,如裁剪后上傳服務(wù)器或者轉(zhuǎn)base64,都是不符合需求的。那么該怎么處理比較好呢?如何以盡量少的網(wǎng)絡(luò)請求、少占用存儲(chǔ)來解決應(yīng)用場景呢?那么,便想到了只用純數(shù)據(jù)來跟我們的功能打交道。
先安利個(gè)裁圖神器cropperjs,個(gè)人認(rèn)為是個(gè)易上手,配置和api方法蠻齊全的一個(gè)組件庫。
項(xiàng)目內(nèi)引入,一定不要漏了引用樣式
import Cropper from 'cropperjs'; import 'cropperjs/dist/cropper.css';
這里我們以react為例
this.state = { width: 640, //圖片展示寬 height: 360, //圖片展示高 imgWidth: 640, //圖片實(shí)際寬 imgHeight: 360, //圖片實(shí)際高 imgLeft: 0, //圖片左偏移 imgTop: 0, //圖片上偏移 editing: false //是否編輯中 } //展示圖片的基本dom結(jié)構(gòu),我們使用外div內(nèi)img的形式,來跟數(shù)據(jù)結(jié)合控制裁剪圖片的展示 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>
簡單來說就是外層元素控制裁剪展示的寬高,同時(shí)根據(jù)項(xiàng)目需求的元素定位也掛在這,內(nèi)部img掛載圖片實(shí)際大小和偏移。
cropperjs初始化后的元素,是會(huì)與初始化對象img處在同一dom層級,也就是說如果我們直接對展示img進(jìn)行初始化的話,編輯區(qū)域展示將會(huì)受父元素,如圖,放大圖片時(shí)候會(huì)不方查看超出部分
所以在這里,為了圖片編輯的自由度,建議分開展示dom與用以初始化cropper對象的dom,在這里編輯區(qū)域?yàn)槿聊粸槔鶕?jù)項(xiàng)目實(shí)際功能區(qū)域進(jìn)行調(diào)整
.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', //使裁剪時(shí)圖片可拖動(dòng) background: false, //因?yàn)槲覀儸F(xiàn)在是全屏可編輯,需要隱藏掉默認(rèn)的背景 } //當(dāng)然還有許多常見的配置項(xiàng),如編輯框尺寸比例等,大家可自行查看api //裁剪保存 save() { const cropBoxData = this.myCropper.getCropBoxData(); //獲取裁剪框數(shù)據(jù) const canvasData = this.myCropper.getCanvasData(); //獲取圖片數(shù)據(jù) this.setState({ width: cropBoxData.width, height: cropBoxData.height, imgLeft: canvasData.left - cropBoxData.left, imgTop: canvasData.top - cropBoxData.top, imgWidth: canvasData.width, imgHeight: canvasData.height }) }
這樣的話 我們就可以完全在自定義的全屏內(nèi)編輯,保存效果如下,到這里我們就完成了第一部分功能,裁剪并保存數(shù)據(jù)和展示
重點(diǎn)介紹下我們用到的兩個(gè)api方法getCropBoxData和getCanvasData,getCanvasData是用來獲取圖片的實(shí)際數(shù)據(jù)的(當(dāng)前的寬高,和相對于父元素可視區(qū)域的位移偏移量),getCropBoxData則是獲取相對于圖片區(qū)域的裁剪區(qū)相關(guān)數(shù)據(jù)。
那么后續(xù)的需求接著來了,我們怎么做到二次編輯的時(shí)候,能還原效果呢,嗯,其實(shí)在前面我們記錄裁圖數(shù)據(jù)的時(shí)候,把相應(yīng)的數(shù)據(jù)關(guān)系再計(jì)算一遍就好了,在初始化cropper的options中增加配置
const options = { dragMode: 'move', background: false, //控件初始化后重置相應(yīng)配置 ready: () => { const { width, height, imgWidth, imgHeight, imgLeft, imgTop } = this.state; //根據(jù)實(shí)際需要出現(xiàn)裁圖功能進(jìn)行定位,此處left和top僅為測試暫時(shí)默認(rèn)值定義 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);
這時(shí)候我們再點(diǎn)擊裁圖,就完美還原了,左邊和上邊的間隙就是setCanvasData的top和left,根據(jù)實(shí)際項(xiàng)目進(jìn)行調(diào)整,setCropBoxData的left和top是相對于cropper-canvas的定位,才有了以上的計(jì)算形式。
此時(shí),基本功能到此結(jié)束,如果說是應(yīng)用在h5編輯中,設(shè)計(jì)到scale縮放的話,相關(guān)的數(shù)據(jù)計(jì)算都要算上scale的縮放值哦,不然就會(huì)出現(xiàn)展示圖片和編輯圖片大小不對等的狀況。同時(shí)還有許多功能就不做展示了,設(shè)置裁剪框比例,編輯縮放等,歡迎嘗試。
當(dāng)然了,如果想要保存圖片,也有相應(yīng)的方法到處裁剪圖片的數(shù)據(jù)
this.myCropper.getCroppedCanvas().toDataURL('image/jpeg')
最后,我們可以看到,在整個(gè)功能過程中,我們需要的只是裁剪的數(shù)據(jù),讀寫快,也不需要進(jìn)行額外的圖片存儲(chǔ),減少文件服務(wù)器存儲(chǔ)的開銷與優(yōu)化。
感謝大家收看,歡迎討論和指正。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JS去掉第一個(gè)字符和最后一個(gè)字符的實(shí)現(xiàn)代碼
本篇文章主要是對JS去掉第一個(gè)字符和最后一個(gè)字符的實(shí)現(xiàn)代碼進(jìn)行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-02-02JS設(shè)計(jì)模式之狀態(tài)模式概念與用法分析
這篇文章主要介紹了JS設(shè)計(jì)模式之狀態(tài)模式概念與用法,簡單講述了狀態(tài)模式的概念、功能、應(yīng)用場景并結(jié)合javascript實(shí)例形式分析了狀態(tài)模式的簡單定義及使用方法,需要的朋友可以參考下2018-02-02Cropper.js進(jìn)階實(shí)現(xiàn)圖片旋轉(zhuǎn)裁剪處理功能示例
這篇文章主要為大家介紹了Cropper.js進(jìn)階實(shí)現(xiàn)圖片旋轉(zhuǎn)裁剪功能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05使用bootstraptable插件實(shí)現(xiàn)表格記錄的查詢、分頁、排序操作
這篇文章主要介紹了 使用bootstraptable插件實(shí)現(xiàn)表格記錄的查詢、分頁、排序操作,需要的朋友可以參考下2017-08-08prototype.js簡單實(shí)現(xiàn)ajax功能示例
這篇文章主要介紹了prototype.js簡單實(shí)現(xiàn)ajax功能,結(jié)合實(shí)例形式分析了prototype.js前臺(tái)實(shí)現(xiàn)ajax與后臺(tái)struts的相關(guān)操作技巧,需要的朋友可以參考下2017-10-10