Vue 實現圖片預覽、裁剪並獲取被裁剪區域的base64(無元件)
阿新 • • 發佈:2018-12-06
前言
最近公司專案需要用到圖片裁剪技術,便著手寫了一個,可以說是用Vue實現的原生裁剪,畢竟也只是去操作dom,不過vue有個黑魔法,ref屬性,使用的方法和原生dom一模一樣但是更節省dom操作時的消耗
裁剪思路
這邊大致介紹一下裁剪圖片的思路,通過input[type=file]將圖片檔案流讀取,轉換成base64後賦給一個img標籤進行顯示出圖片,實現圖片預覽,在img標籤的背後放一個寬高和它一樣的canvas並把剛才獲取的base64給canvas,此時就是一張img圖片在上一張canvas圖片在下(兩個同一張圖),之後用clip(之後會專門發一篇部落格供大家理解clip的使用)對圖片進行矩形裁剪,雖說是裁剪不過只是視覺上的裁剪,圖片的base64仍然和原來一樣。將傳入clip的4個屬性值轉換成被裁剪圖片對應在原圖片的x軸,y軸,矩形區域寬,矩形區域高,將這些引數通過canvas的getImageData方法傳進去可以獲得剛才背後的canvas所對應區域的一個canvas區域(就是我們裁剪的區域,該區域的x,y寬,高和原圖片clip所視覺裁剪的一樣),然後我們新建一個canvas標籤,通過putImageData方法,將這個通過getImageData得到的資料賦給新建立的canvas,在通過toDataURL方法輸出新建canvas的base64,大致思路是這樣,可能還有點懵,下面上程式碼和解析,為了更加逼真,在裁剪時我多添加了一個黑色背景
<template>
<div>
<input type="file" @change="selectImage($event)">
<div class="canvasDiv" v-if="showImg">
<!--img背後的canvas-->
<canvas ref="canvas" class="canvas"></canvas>
<!--裁剪時候的背景-->
<div class="bg" @mouseup="mouseupEvent($event)" ></div>
<!--需要裁剪的圖片-->
<img ref="img" class="img">
<!--裁剪圖片區域內的div,為了通過滑鼠拖拽進行生成裁剪區域-->
<div class="mouseDiv"
@mousedown="mousedownEvent($event)"
@mouseup="mouseupEvent($event)"
@mousemove="mousemoveEvent($event)"
>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
showImg:false,
imgType:false,
pointX:0,
pointY:0,
canvasStyle:{}
}
},
methods:{
//檔案流匯出
selectImage(event){
//獲取input[type=file]
let file = event.currentTarget;
if(!file.files || !file.files[0]){
return;
}
this.showImg = true;
let reader = new FileReader();
//讀取檔案流
reader.onload = (evt)=>{
/*
this.$refs.img.src相當於對img節點的src屬性操作
evt.target.result為圖片檔案裝換的base64編碼
*/
this.$refs.img.src = evt.target.result;
let imgDOM = this.$refs.img;
//當節點渲染完之後
this.$nextTick(()=>{
//通過Image將在圖片背後的canvas畫出來
let myImg = new Image();
myImg.onload = ()=>{
//這裡一點要乘2,否則顯示出來的比例不正常,下面的一些程式碼也是
this.$refs.canvas.width = imgDOM.offsetWidth * 2;
this.$refs.canvas.height = imgDOM.offsetHeight * 2;
//畫背後canvas
this.$refs.canvas.getContext('2d').drawImage(myImg,0,0, imgDOM.offsetWidth * 2 , imgDOM.offsetHeight * 2 ,);
}
myImg.src = evt.target.result;
})
}
reader.readAsDataURL(file.files[0]);
},
//獲取滑鼠剛要擷取的位置
mousedownEvent(event){
this.imgType = true;
this.pointX = event.offsetX;
this.pointY = event.offsetY;
},
//當滑鼠鬆開時候(即形成拖拽區域結束)
mouseupEvent(event){
this.imgType = false;
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
this.$nextTick(()=>{
//將img被裁剪的x,y,w,h所對應的canvas區域拿出來
let imgData = this.$refs.canvas.getContext('2d').getImageData(
this.canvasStyle.x * 2,
this.canvasStyle.y * 2,
this.canvasStyle.w * 2,
this.canvasStyle.h * 2);
canvas.width = this.canvasStyle.w * 2;
canvas.height = this.canvasStyle.h * 2;
//將裁剪的區域給新建立的canvas
ctx.putImageData(imgData,0,0,0,0, this.canvasStyle.w * 2, this.canvasStyle.h * 2);
//輸出base64
console.log(canvas.toDataURL("image/jpeg"));
// window.open(canvas.toDataURL("image/jpeg"));
})
},
//滑鼠拖拽(通過一個引數imgType控制,當滑鼠按下並移動時候才觸發實現拖拽)
mousemoveEvent(event){
if(this.imgType){
//獲取滑鼠拖動的矩形區域
let x = event.offsetX;
let y = event.offsetY;
let top = y < this.pointY ? y : this.pointY;
let right = x > this.pointX ? x : this.pointX;
let bottom = y > this.pointY ? y : this.pointY;
let left = x < this.pointX ? x : this.pointX;
this.canvasStyle = {
x:left,
y:top,
w:right - left,
h:bottom - top,
}
//對圖片進行裁剪
this.$refs.img.style.clip = `rect(${top}px,${right}px,${bottom}px,${left}px)`;
}
},
}
}
</script>
<style scoped>
.canvasDiv{
position: fixed;
width: 500px;
left: calc(50% - 250px);
top: 100px;
}
.bg{
position: fixed;
width: 100%;
height: 100%;
background: black;
opacity: 0.5;
top: 0;
left: 0;
z-index: 2;
}
.img{
position: absolute;
width: 500px;
top: 0;
left:0;
z-index: 3;
user-select: none;
}
.mouseDiv{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 10;
}
.canvas{
width: 100%;
}
</style>
效果預覽
以上就是全部內容,如果寫的不對或者不好還請大佬們諒解!!
clip屬性引數詳解