1. 程式人生 > >Vue 實現圖片預覽、裁剪並獲取被裁剪區域的base64(無元件)

Vue 實現圖片預覽、裁剪並獲取被裁剪區域的base64(無元件)

前言

    最近公司專案需要用到圖片裁剪技術,便著手寫了一個,可以說是用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屬性引數詳解