Vue實(shí)現(xiàn)簡單基礎(chǔ)的圖片裁剪功能
近日,在寫公司項(xiàng)目的時(shí)候接到一個(gè)需求:對(duì)已加載的大圖中可截取部分圖片用來入庫或者布控,說白了就是截圖嘛,于是我使用了vue-cropper來完成。完成后因?yàn)榍斑呉矝]自己實(shí)現(xiàn)過,所以就想看看是如何實(shí)現(xiàn)的。因此本文寫的是最簡易基礎(chǔ)的實(shí)現(xiàn)方法用作學(xué)習(xí),肯定有考慮不周的地方,還請(qǐng)大家諒解。工作中還是使用成熟的輪子為好。
一、準(zhǔn)備工作
本文中我所使用的環(huán)境為vue2 ?,F(xiàn)在可以在隨便一個(gè)vue項(xiàng)目中新建一個(gè)vue文件開始了。
二、基本結(jié)構(gòu)
在本文中會(huì)使用到兩個(gè)canvas,一個(gè)用來繪制我們要加載的圖片,一個(gè)用來繪制矩形框選區(qū)域,就像下面這樣,并且在兩個(gè)canvas身上分別加上ref屬性。
html
<template>
<div>
<div class="wrap">
<canvas id="canvas" ref="imgCanvas"></canvas>
<canvas
id="drawCanvas"
ref="drawCanvas"
></canvas>
</div>
</div>
</template>下方樣式設(shè)置兩個(gè)canvas重疊
<style>
#drawCanvas {
position: absolute;
top: 0;
left: 0;
}
.wrap {
position: relative;
}
</style>三、添加功能
首先我們需要將兩個(gè)canvas的寬高都設(shè)置為相同的,由于上面沒有設(shè)置canvas的寬高,因此我們?cè)赿ata選項(xiàng)中添加好需要的寬高數(shù)據(jù) width: 500,height: 300,稍后將它設(shè)置為canvas的大小,請(qǐng)記住,不要用css設(shè)置canvas的大小,這其實(shí)是將canvas拉伸了。然后在data中添加 ctx 和 imgCtx兩個(gè)屬性用于保存上下文。 接著在mounted生命周期中對(duì)canvas進(jìn)行操作,并且獲取到要加載的圖片
let imgCanvas = this.$refs.imgCanvas;//繪制圖片的canvas
let drawCanvas = this.$refs.drawCanvas;//繪制框選款的canvas
//設(shè)置兩個(gè)canvas的寬高
imgCanvas.width = this.width;
imgCanvas.height = this.height;
drawCanvas.width = this.width;
drawCanvas.height = this.height;
//獲取兩個(gè)canvas的上下文并且保存在data中
this.ctx = drawCanvas.getContext("2d");
this.imgCtx = imgCanvas.getContext("2d");
//加載圖片
let img = new Image();
img.src = "https://www.auok.ltd/background.jpg";
img.crossOrigin = "anonymous";
img.onload = () => {
console.log("加載完成", img);
//圖片加載完成后開始繪制圖片
this.imgCtx.drawImage(img, 0, 0, this.width, this.height);
};以上步驟搞定后現(xiàn)在的頁面中應(yīng)該如下面一樣了

接下來讓我們給drawCanvas添加事件監(jiān)聽。需要監(jiān)聽的事件有以下幾個(gè)
- 鼠標(biāo)按下
- 鼠標(biāo)抬起
- 鼠標(biāo)移動(dòng)
- 鼠標(biāo)移出
我們來改寫一下模板結(jié)構(gòu),像下面這樣
<template>
<div>
<div class="wrap">
<canvas id="canvas" ref="imgCanvas"></canvas>
<canvas
id="drawCanvas"
ref="drawCanvas"
@mousedown="onMouseDown"
@mousemove="onMouseMove"
@mouseup="onMouseUp"
@mouseleave="onMouseLeave"
></canvas>
</div>
<img :src="curSrc" alt="" style="margin: 10px 10px 0 0" />
<canvas id="outCanvas"></canvas>
</div>
</template>然后在methods中添加對(duì)應(yīng)的onMouseDown、onMouseUp、onMouseMove、onMouseLeave四個(gè)方法。然后我們來編寫這四個(gè)方法就好
onMouseDown
這個(gè)方法是鼠標(biāo)按下事件的監(jiān)聽處理函數(shù)。主要負(fù)責(zé)以下幾點(diǎn)
- 清除drawCanvas
- 獲取鼠標(biāo)按下時(shí)的位置
- 設(shè)置一下繪制線條的樣式
代碼如下: 編寫這個(gè)方法前我們要現(xiàn)在data中增加ddownPoint和down兩個(gè)屬性用來存儲(chǔ)點(diǎn)的位置和標(biāo)識(shí)鼠標(biāo)是否按下。
onMouseDown(e) {
console.log("鼠標(biāo)按下", e.offsetX, e.offsetY);
this.downPoint = [e.offsetX, e.offsetY];
this.down = true;
this.ctx.strokeStyle = "#fff";
this.ctx.lineWidth = 2;
}onMouseMove
鼠標(biāo)按下了,下面就要移動(dòng)了。此方法是鼠標(biāo)移動(dòng)的監(jiān)聽處理函數(shù)。負(fù)責(zé)以下幾點(diǎn)
- 獲取鼠標(biāo)移動(dòng)的位置
- 繪制矩形選框
- 繪制遮罩層
onMouseMove(e) {
//鼠標(biāo)未按下不執(zhí)行操作
if (!this.down) {
return;
}
console.log("鼠標(biāo)移動(dòng)", e.offsetX, e.offsetY);
//當(dāng)前鼠標(biāo)移動(dòng)的位置
let movePoint = [e.offsetX, e.offsetY];
this.ctx.fillStyle = "rgba(0,0,0,.5)";//設(shè)置遮罩層填充顏色
//清空drawCanvas
this.ctx.clearRect(0, 0, this.width, this.height);
//使用設(shè)置的填充顏色來設(shè)置drawCanvas的顏色
this.ctx.fillRect(0, 0, this.width, this.height);
//清除指定區(qū)域的顏色,因?yàn)樾枰L制的選框中間是沒有顏色的,不然的話選框區(qū)域都是遮罩層的顏色。如下圖
this.ctx.clearRect(
downPoint[0],
downPoint[1],
movePoint[0] - this.downPoint[0],
movePoint[1] - this.downPoint[1]
);
//繪制描邊矩形 四個(gè)參數(shù)是x坐標(biāo) , y坐標(biāo) , 矩形的長,矩形的寬
this.ctx.strokeRect(
downPoint[0],
downPoint[1],
movePoint[0] - this.downPoint[0],
movePoint[1] - this.downPoint[1]
);
},
onMouseUp
這個(gè)方法是鼠標(biāo)松開按鍵的事件處理函數(shù),主要負(fù)責(zé)
- 獲取鼠標(biāo)松開的坐標(biāo)
- 獲取框選部分的圖片 上面的步驟中截圖區(qū)域已經(jīng)選擇完成。接下來就是要獲取截圖部分的圖片了。
代碼如下
onMouseUp(e) {
console.log("鼠標(biāo)抬起", e.offsetX, e.offsetY);
//獲取坐標(biāo)
let upPoint = [e.offsetX, e.offsetY];
//重置鼠標(biāo)按下狀態(tài)
this.down = false;
//獲取指定區(qū)域的圖片數(shù)據(jù)
let cutImgData = this.imgCtx.getImageData(
this.downPoint[0],
this.downPoint[1],
upPoint[0] - this.downPoint[0],
upPoint[1] - this.downPoint[1]
);
//獲取返回的圖片數(shù)據(jù)中的寬高
let { width, height } = cutImgData;
console.log(cutImgData);
//創(chuàng)建一個(gè)用于放置圖片的canvas用來輸出圖片
let outCanvas = document.createElement("canvas");
let outCtx = outCanvas.getContext("2d");
outCanvas.height = height;
outCanvas.width = width;
//將圖片放置到canvas上
outCtx.putImageData(cutImgData, 0, 0);
//以blob的形式輸出圖片
outCanvas.toBlob((blob) => {
this.curSrc = URL.createObjectURL(blob);
}通過調(diào)用getImageData獲取了圖片指定區(qū)域的數(shù)據(jù),然后將獲取到的圖片數(shù)據(jù)使用putImageData放到創(chuàng)建好的canvas中,再通過canvas的toBlob或者toDataURL方法就可以輸入圖片的二進(jìn)制數(shù)據(jù)或者base64字符串了,這里我用的是blob,再通過URL.createObjectURL獲取到圖片的本地地址,這種形式:blob:http://localhost:8080/e835d581-cdfe-48ff-b562-743bfcd4970d,可以用來顯示或者上傳。 在模板中添加一個(gè)img標(biāo)簽,并且在data中添加cruSrc屬性,最后就如下圖
<img :src="curSrc" alt="" style="margin: 10px 10px 0 0" />

onMouseLeave
這個(gè)方法是在鼠標(biāo)移出canvas區(qū)域后重置canvas的狀態(tài)的。將鼠標(biāo)狀態(tài)down重置為false,然后再清除canvas。
四、總結(jié)
如果要實(shí)際的實(shí)現(xiàn)一個(gè)和vue-cropper功能差不多的是比較復(fù)雜,要考慮很多東西,比如圖像的縮放比例、選框的移動(dòng)及大小調(diào)整之類的。這些部分還沒有寫。
以上就是Vue實(shí)現(xiàn)簡單基礎(chǔ)的圖片裁剪功能的詳細(xì)內(nèi)容,更多關(guān)于Vue圖片裁剪的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue-Router基礎(chǔ)學(xué)習(xí)筆記(小結(jié))
這篇文章主要介紹了Vue-Router基礎(chǔ)學(xué)習(xí)筆記(小結(jié)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10
Vue實(shí)現(xiàn)導(dǎo)航欄的顯示開關(guān)控制
今天小編就為大家分享一篇Vue實(shí)現(xiàn)導(dǎo)航欄的顯示開關(guān)控制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11
Vue.js 帶下拉選項(xiàng)的輸入框(Textbox with Dropdown)組件
這篇文章主要介紹了Vue.js 帶下拉選項(xiàng)的輸入框(Textbox with Dropdown)組件,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
vue3+ts+vite+electron搭建桌面應(yīng)用的過程
這篇文章主要介紹了vue3+ts+vite+electron搭建桌面應(yīng)用的過程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
AntV F2和vue-cli構(gòu)建移動(dòng)端可視化視圖過程詳解
這篇文章主要介紹了AntV F2和vue-cli構(gòu)建移動(dòng)端可視化視圖過程詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
新手vue構(gòu)建單頁面應(yīng)用實(shí)例代碼
本篇文章主要介紹了新手vue構(gòu)建單頁面應(yīng)用實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09
vue自定義標(biāo)簽和單頁面多路由的實(shí)現(xiàn)代碼
這篇文章主要介紹了vue自定義標(biāo)簽和單頁面多路由的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05
在vue中使用css modules替代scroped的方法
本篇文章主要介紹了在vue中使用css modules替代scroped的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-03-03

