詳解vue項目中實(shí)現(xiàn)圖片裁剪功能
演示地址
https://my729.github.io/picture-crop-demo/dist/#/
前言
- vue版本:3.6.3 https://cli.vuejs.org/zh/
- cropperjs: 1.5.1 https://github.com/fengyuanchen/cropperjs
- elementUI https://element.eleme.io/#/zh-CN
使用 cropperjs插件 和 原生canvas 兩種方式實(shí)現(xiàn)圖片裁剪功能
使用cropperjs插件
安裝cropperjs
yarn install cropperjs
初始化一個canvas元素,并在上面繪制圖片
<canvas :id="data.src" ref="canvas"></canvas>
// 在canvas上繪制圖片
drawImg () {
this.$nextTick(() => {
// 獲取canvas節(jié)點(diǎn)
let canvas = document.getElementById(this.data.src)
if (canvas) {
// 設(shè)置canvas的寬為canvas的父元素寬度,寬高比3:2
let parentEle = canvas.parentElement
canvas.width = parentEle.offsetWidth
canvas.height = 2 * parentEle.offsetWidth / 3
let ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, canvas.width, canvas.height)
let img = new Image()
img.crossOrigin = 'Anonymous'
img.src = this.data.src
img.onload = function () {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
}
}
})
}
如果遇到canvas跨域繪制圖片報錯,設(shè)置圖片img.crossOrigin = 'Anonymous',并且服務(wù)器響應(yīng)頭設(shè)置Access-Control-Allow-Origin:*
創(chuàng)建cropperjs
// 引入
import Cropper from 'cropperjs'
// 顯示裁剪框
initCropper () {
let cropper = new Cropper(this.$refs.canvas, {
checkCrossOrigin: true,
viewMode: 2,
aspectRatio: 3 / 2
})
}
更多方法和屬性,參考官網(wǎng): https://github.com/fengyuanchen/cropperjs
具體實(shí)現(xiàn),可以查看源碼的cropper.vue 或 cropper.one.vue組件:
cropper.vue組件:https://github.com/MY729/picture-crop-demo/blob/master/src/components/cropper.vue
cropper.one.vue組件:https://github.com/MY729/picture-crop-demo/blob/master/src/components/cropper.one.vue
使用canvas實(shí)現(xiàn)圖片裁剪
支持鼠標(biāo)繪制裁剪框,并移動裁剪框
思路:
- 在canvas上繪制圖片為背景
- 監(jiān)聽鼠標(biāo)點(diǎn)擊、移動、松開事件
canvas的isPointInPath()方法: 如果給定的點(diǎn)的坐標(biāo)位于路徑之內(nèi)的話(包括路徑的邊),否則返回 false
具體實(shí)現(xiàn)可查看源碼cropper.canvas.vue組件: https://github.com/MY729/picture-crop-demo/blob/master/src/components/cropper.canvas.vue
cropImg () {
let canvas = document.getElementById(this.data.img_url)
let ctx = canvas.getContext('2d')
let img = new Image()
img.onload = function () {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
}
img.src = this.data.src
let drag = false // 是否拖動矩形
let flag = false // 是否繪制矩形
let rectWidth = 0 // 繪制矩形的寬
let rectHeight = 0 // 繪制矩形的高
let clickX = 0 // 矩形開始繪制X坐標(biāo)
let clickY = 0 // 矩形開始繪制Y坐標(biāo)
let dragX = 0 // 當(dāng)要拖動矩形點(diǎn)擊時X坐標(biāo)
let dragY = 0 // 當(dāng)要拖動矩形點(diǎn)擊時Y坐標(biāo)
let newRectX = 0 // 拖動變化后矩形開始繪制的X坐標(biāo)
let newRectY = 0 // 拖動變化后矩形開始繪制的Y坐標(biāo)
// 鼠標(biāo)按下
canvas.onmousedown = e => {
// 每次點(diǎn)擊前如果有繪制好的矩形框,通過路徑繪制出來,用于下面的判斷
ctx.beginPath()
ctx.setLineDash([6, 6])
ctx.moveTo(newRectX, newRectY)
ctx.lineTo(newRectX + rectWidth, newRectY)
ctx.lineTo(newRectX + rectWidth, newRectY + rectHeight)
ctx.lineTo(newRectX, newRectY + rectHeight)
ctx.lineTo(newRectX, newRectY)
ctx.strokeStyle = 'green'
ctx.stroke()
// 每次點(diǎn)擊,通過判斷鼠標(biāo)點(diǎn)擊的點(diǎn)在矩形框內(nèi)還是外,來決定重新繪制還是移動矩形框
if (ctx.isPointInPath(e.offsetX, e.offsetY)) {
drag = true
dragX = e.offsetX
dragY = e.offsetY
clickX = newRectX
clickY = newRectY
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
flag = true
clickX = e.offsetX
clickY = e.offsetY
newRectX = e.offsetX
newRectY = e.offsetY
}
}
// 鼠標(biāo)抬起
canvas.onmouseup = () => {
if (flag) {
flag = false
this.sureCrop(clickX, clickY, rectWidth, rectHeight)
}
if (drag) {
drag = false
this.sureCrop(newRectX, newRectY, rectWidth, rectHeight)
}
}
// 鼠標(biāo)移動
canvas.onmousemove = (e) => {
if (flag) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
rectWidth = e.offsetX - clickX
rectHeight = e.offsetY - clickY
ctx.beginPath()
ctx.strokeStyle = '#FF0000'
ctx.strokeRect(clickX, clickY, rectWidth, rectHeight)
ctx.closePath()
}
if (drag) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
ctx.beginPath()
newRectX = clickX + e.offsetX - dragX
newRectY = clickY + e.offsetY - dragY
ctx.strokeStyle = 'yellow'
ctx.strokeRect(newRectX, newRectY, rectWidth, rectHeight)
ctx.closePath()
}
}
},
// 拿到裁剪后的參數(shù),可自行處理圖片
sureCrop (x, y, width, height) {
let canvas = document.getElementById(this.data.img_url + 'after')
// 設(shè)置canvas的寬為canvas的父元素寬度,寬高比3:2
let parentEle = canvas.parentElement
canvas.width = parentEle.offsetWidth
canvas.height = 2 * parentEle.offsetWidth / 3
let ctx = canvas.getContext('2d')
let img = new Image()
img.src = this.data.src
img.onload = function () {
ctx.beginPath()
ctx.moveTo(x, y)
ctx.lineTo(x + width, y)
ctx.lineTo(x + width, y + height)
ctx.lineTo(x, y + height)
ctx.clip()
ctx.drawImage(img, 0, 0, canvas.width, canvas.height)
}
ctx.stroke()
}
源碼地址
https://github.com/MY729/picture-crop-demo
可以直接clone項目,本地運(yùn)行查看代碼和效果
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。
- vue+element實(shí)現(xiàn)圖片上傳及裁剪功能
- vue實(shí)現(xiàn)移動端圖片裁剪上傳功能
- vue-cli結(jié)合Element-ui基于cropper.js封裝vue實(shí)現(xiàn)圖片裁剪組件功能
- Vue-cropper 圖片裁剪的基本原理及思路講解
- vue移動端裁剪圖片結(jié)合插件Cropper的使用實(shí)例代碼
- 基于Vue的移動端圖片裁剪組件功能
- cropper js基于vue的圖片裁剪上傳功能的實(shí)現(xiàn)代碼
- vue-image-crop基于Vue的移動端圖片裁剪組件示例
- vue.js 實(shí)現(xiàn)圖片本地預(yù)覽 裁剪 壓縮 上傳功能
- vue-cropper實(shí)現(xiàn)裁剪圖片
相關(guān)文章
vue如何轉(zhuǎn)換時間格式為年月日時分秒和年月日(補(bǔ)零)
這篇文章主要介紹了vue如何轉(zhuǎn)換時間格式為年月日時分秒和年月日(補(bǔ)零),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04
Vue動態(tài)構(gòu)建混合數(shù)據(jù)Treeselect選擇樹及巨樹問題的解決
這篇文章主要介紹了Vue動態(tài)構(gòu)建混合數(shù)據(jù)Treeselect選擇樹及巨樹問題的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
vuex中store存儲store.commit和store.dispatch的用法
這篇文章主要介紹了vuex中store存儲store.commit和store.dispatch的用法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07
vite+vue3中使用mock模擬數(shù)據(jù)問題
這篇文章主要介紹了vite+vue3中使用mock模擬數(shù)據(jù)問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03

