Vue 实现图片预览、裁剪并获取被裁剪区域的base64(无组件)
前言最近公司项目需要用到图片裁剪技术,便着手写了一个,可以说是用Vue实现的原生裁剪,毕竟也只是去操作dom,不过vue黑魔法有个ref属性,使用的方法和原生dom一模一样但是更节省dom操作的消耗裁剪思路这边大致介绍一下裁剪图片的思路,通过input[type=file]将图片文件流读取,转换成base64后给img标签进行图片预览,在img标签的背后放一个宽高和它一样的canvas并把刚才获取
关注公众号,每天领外卖红包
前言
最近公司项目需要用到图片裁剪技术,便着手写了一个,可以说是用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属性参数详解
更多推荐
所有评论(0)