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

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
Vue 3.0中实现base64图片预览放大缩小,可以使用VueCropper组件。以下是实现步骤: 1. 安装VueCropper组件库:在终端中运行以下命令进行安装:npm install vue-cropper 2. 引入VueCropper组件库:在需要使用的Vue组件中,使用import语句引入VueCropper组件库。 3. 在Vue组件中使用VueCropper组件:在Vue组件的template中,使用VueCropper组件的标签,并设置相关属性,如:src、outputType、canMove、autoCrop等。 4. 定义props传参:在Vue组件的script中,定义props传参,如:src、outputType、canMove、autoCrop等。 5. 编写核心方法:在Vue组件的script中,编写核心方法,如:onCrop、onZoom、onRotate等。 6. 在Vue组件中使用TipsDialog组件:在Vue组件的template中,使用TipsDialog组件的标签,并设置相关属性,如:title、content、visible等。 以下是一个简单的示例代码: ``` <template> <div> <vue-cropper ref="cropper" :src="imgSrc" :output-type="'jpeg'" :can-move="true" :auto-crop="true" @crop="onCrop" @zoom="onZoom" @rotate="onRotate" ></vue-cropper> <tips-dialog :title="'Tips'" :content="'Please crop the image.'" :visible="showTipsDialog" ></tips-dialog> </div> </template> <script> import { VueCropper } from 'vue-cropper' import TipsDialog from './TipsDialog.vue' export default { components: { VueCropper, TipsDialog }, props: { imgSrc: { type: String, required: true } }, data() { return { showTipsDialog: true } }, methods: { onCrop() { // 处理裁剪后的图片 }, onZoom() { // 处理缩放后的图片 }, onRotate() { // 处理旋转后的图片 } } } </script> ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hhzzcc_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值