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属性参数详解

猜你喜欢

转载自blog.csdn.net/hhzzcc_/article/details/80324546