图片截取组件vue-cropper

2,885 阅读4分钟

vue-cropper 一个优雅的图片裁剪插件

一、安装使用

1. 安装

# npm 安装
npm install vue-cropper
# yarn 安装
yarn add vue-cropper

2. 引入

main.js 引入

import VueCropper from 'vue-cropper'
Vue.use(VueCropper)

vue 组件引入 VueCropper

import { VueCropper }  from 'vue-cropper' 
components: {
  VueCropper
}

CDN 方式引入

<script src="//cdn.jsdelivr.net/npm/vue-cropper@0.4.9/dist/index.js"></script>
Vue.use(window['vue-cropper'].default)

3. 代码中使用

官方说明:

**重要!**需要关掉本地的 mock 服务, 不然图片转化会报错

**重要!**需要使用外层容器包裹并设置宽高

<div style="width: 200px; height: 200px">  
  <vue-cropper
    ref="cropper"
    :img="option.img" // url地址base64blob
    autoCrop
    autoCropWidth="150"
    autoCropHeight="150"
    centerBox
    fixed
    :enlarge="option.enlarge"
    :canMove="false"
    @realTime="realTime"
    outputType="png"
  />
</div>

二、文档

1. props

官方说明:目前还不知道什么原因项目里面开启 mock 会导致 file 报错,建议使用时关掉 mock

名称功能默认值可选值
img裁剪图片的地址url 地址, base64, blob
outputSize裁剪生成图片的质量10.1 ~ 1
outputType裁剪生成图片的格式jpg (jpg 需要传入jpeg)jpeg, png, webp
info裁剪框的大小信息truetrue, false
canScale图片是否允许滚轮缩放truetrue, false
autoCrop是否默认生成截图框falsetrue, false
autoCropWidth默认生成截图框宽度容器的 80%0 ~ max
autoCropHeight默认生成截图框高度容器的 80%0 ~ max
fixed是否开启截图框宽高固定比例truetrue, false
fixedNumber截图框的宽高比例[1, 1][ 宽度 , 高度 ]
full是否输出原图比例的截图falsetrue, false
fixedBox固定截图框大小不允许改变false
canMove上传图片是否可以移动truetrue, false
canMoveBox截图框能否拖动truetrue, false
original上传图片按照原始比例渲染falsetrue, false
centerBox截图框是否被限制在图片里面falsetrue, false
high是否按照设备的dpr 输出等比例图片truetrue, false
infoTruetrue 为展示真实输出图片宽高 false 展示看到的截图框宽高falsetrue, false
maxImgSize限制图片最大宽度和高度20000 ~ max
enlarge图片根据截图框输出比例倍数10 ~ max(建议不要太大不然会卡死)
mode图片默认渲染方式containcontain , cover, 100px, 100% auto

2. props 可用回调方法

  • @realTime 实时预览事件
  • @imgMoving 图片移动回调函数
  • @cropMoving 截图框移动回调函数
  • @imgLoad 图片加载的回调, 返回结果 success, error
@realTime 实时预览事件
realTime(data) {
  var previews = data
  var h = 0.5
  var w = 0.2

  this.previewStyle1 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: h
  }

  this.previewStyle2 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: w
  }

  // 固定为 100 宽度
  this.previewStyle3 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: 100 / preview.w
  }

  // 固定为 100 高度
  this.previewStyle4 = {
    width: previews.w + "px",
    height: previews.h + "px",
    overflow: "hidden",
    margin: "0",
    zoom: 100 / preview.h
  }
  this.previews = data
}
<div class="show-preview" :style="{'width': previews.w + 'px', 'height': previews.h + 'px',  'overflow': 'hidden',
    'margin': '5px'}">
  <div :style="previews.div">
    <img :src="option.img" :style="previews.img">
  </div>
</div>
<p>中等大小</p>
<div :style="previewStyle1"> 
  <div :style="previews.div">
    <img :src="previews.url" :style="previews.img">
  </div>
</div>

<p>迷你大小</p>
<div :style="previewStyle2"> 
  <div :style="previews.div">
    <img :src="previews.url" :style="previews.img">
  </div>
</div>
@imgMoving 图片移动回调函数

返回的参数内容

{
   moving: true, // moving 是否在移动
   axis: {
     x1: 1, // 左上角
     x2: 1// 右上角
     y1: 1// 左下角
     y2: 1 // 右下角
   }
 }
@cropMoving 截图框移动回调函数

返回的参数内容

{
   moving: true, // moving 是否在移动
   axis: {
     x1: 1, // 左上角
     x2: 1// 右上角
     y1: 1// 左下角
     y2: 1 // 右下角
   }
 }
@imgLoad图片加载回调函数

返回的参数内容

success,error

3. 内置属性与方法

通过 this.$refs.cropper 调用

属性
属性说明
this.$refs.cropper.cropW截图框宽度
this.$refs.cropper.cropH截图框高度
方法
方法说明
this.$refs.cropper.startCrop()开始截图
this.$refs.cropper.stopCrop()停止截图
this.$refs.cropper.clearCrop()清除截图
this.$refs.cropper.changeScale()修改图片大小 正数为变大 负数变小
this.$refs.cropper.getImgAxis()获取图片基于容器的坐标点
this.$refs.cropper.getCropAxis()获取截图框基于容器的坐标点
this.$refs.cropper.goAutoCrop自动生成截图框函数
this.$refs.cropper.rotateRight()向右边旋转90度
this.$refs.cropper.rotateLeft()向左边旋转90度
获取截图内容
  1. 获取截图的 base64 数据

    this.$refs.cropper.getCropData(data => {
      // do something
      console.log(data)  
    })
    
  2. 获取截图的 blob 数据

    this.$refs.cropper.getCropBlob(data => {
      // do something
      console.log(data)  
    })
    

三、实际操作

1. 截图边框可调整,实时预览,生成图片功能

template

<template>
  <div>
    <!-- 上传图片 -->
    <input type="file" accept="image/*" @change="getFileStream($event)">
    <!-- 图片截图 -->
    <div style="width: 200px; height: 200px">
      <vue-cropper
        ref="cropper"
        :img="option.img"
        autoCrop
        autoCropWidth="150"
        autoCropHeight="150"
        centerBox
        fixed
        :enlarge="option.enlarge"
        :canMove="false"
        @realTime="realTime"
        @imgMoving="imgMoving"
        @cropMoving="cropMoving"
        @imgLoad="imgLoad"
        outputType="png"
      />
    </div>
      
    <div>实时预览</div>
    <div class="show-preview" :style="previewStyle">
      <div :style="previews.div">
        <img :src="previews.url" :style="previews.img" />
      </div>
    </div>
	
    <div>生成图片</div>
    <div>
      <button @click="getCropData()">获取CropBase64数据</button>
      <img :src="base64" alt="base64" />
    </div>
  </div>
</template>

data

data() {
  return {
    option: {
      img: "https://shnhz.github.io/shn-ui/img/Koala.jpg",
    },
    previews: {},
    previewStyle: {},
    base64: "",
    enlarge: 1,
  };
}

methods

methods: {
    // 生成图片
    getCropData() {
      this.$refs.cropper.getCropData((data) => {
        // 输出 base64
        // console.log(data);
        this.base64 = data;
      });
    },
    // 预览图片
    realTime(data) {
      this.previews = data;
      this.option.enlarge = 200 / this.previews.w
      this.previewStyle = {
        width: this.previews.w + "px",
        height: this.previews.h + "px",
        overflow: "hidden",
        margin: "0",
        // 固定宽度200 截图框若小了则放大内容 大了则缩小内容
        zoom: 200 / this.previews.w
      };
    }
}

预览图使用了 zoom 缩放原理:固定高度或宽度px值 / 变化的宽度或高度

若变化宽/高度越大则为缩小图片内容,边框宽高度固定

若变化宽/高度越小则为放大图片内容,边框宽高度固定

2. 截图边框固定,图片可调整,实时预览,生成图片功能

templatedatamethods与实际操作 1 中一致,只需更改属性canMoveBoxfixedBox

使用组件自带属性props:canMoveBox [截图框能否拖动]、fixedBox [固定截图框大小]

设置 :canMoveBox="false" 在截图框后的图片可以拖拉缩放

设置 fixedBox 为 true 固定截图框大小

PS:可以添加截图边框样式以及其他样式

style

// 设置截图边框为⚪
<style scoped>
/deep/.cropper-view-box{
  border-radius: 50%;
}
/deep/.cropper-face{
  border-radius: 50%;
}
</style>

3. 结果

操作 1 中实现结果:

image-20211104160108354.png

操作 2 中实现结果:

image-20211104160642174.png

四、最后

简单实现了上传图片文件至截图框内,实现如下:

使用 input 标签,设置 type=“file” 接收 accept 为图像,并设置了 change 事件

template

<!-- 上传图片 -->
<input type="file" accept="image/*" @change="getFileStream($event)">

methods

// 获取文件流
getFileStream(e){
  this.fileToImg(e.target.files[0])
},
// 上传文件转换成 image base64格式
fileToImg(file) {
  var reader = new FileReader()
  // 读取操作成功完成触发
  reader.onload = (e) =>{
    // 将 vue-cropper 中 img 属性值设置为上传文件数据
    this.option.img = e.target.result
  }
  // 将文件读取后返回URL(base64)
  reader.readAsDataURL(file)
}