程沛权
程沛权

Vue 3.0图片裁切插件:vue-picture-cropper

作者:程沛权2020/11/16
Star on GitHub

一个基于 cropper.js ,支持 Vue 3.0 的图片裁切工具组件(目前仅支持 Vue 3.x )。

对 Vue 3.0 还不熟悉的同学,可以查阅我之前总结的文档 《Vue3.0学习教程与实战案例》

GitHub: https://github.com/chengpeiquan/vue-picture-cropper

NPM: https://www.npmjs.com/package/vue-picture-cropper

demo

根据平时常见的使用习惯,弄了一个简单的在线 DEMO ,点击按钮选择图片后,弹出裁切框,裁切后生成裁切结果。

点击查看:vue-picture-cropper-demo

vue-picture-cropper-demo

安装

npm install --save-dev vue-picture-cropper

导入

目前仅支持在 Vue 组件里按需引入,模板和实例也仅限在组件内使用,根据 Vue 3.x 的设计思想,官方也不推荐全局导入各类插件。

// xxx.vue
import VuePictureCropper, { cropper } from 'vue-picture-cropper'

需要注意的是,如果是基于 Vite 的项目,由于 Vite 需要使用 ESM 组件,所以导入方式需要改成从 ESM 版本导入:

// xxx.vue(注意 from 后面的路径不同)
import VuePictureCropper, { cropper } from 'vue-picture-cropper/dist/esm'

导入的模块说明:

模块名称作用
VuePictureCropper组件的模板,用于挂载和渲染,可自定义命名
cropper工具实例,可用于操作相关的api,必须用花括号导入该名称

对 Vue 3.x 还不熟悉的同学,请看下方的用法示范。

用法

工具的渲染方法如下,请注意在 Vue 3.x 里,除非你使用 class 风格来编写组件,否则组件都需要通过 defineComponent 来定义。

<template>
  <vue-picture-cropper
    :boxStyle="{
      width: '100%',
      height: '100%',
      backgroundColor: '#f8f8f8',
      margin: 'auto'
    }"
    :img="pic"
    :options="{
      viewMode: 1,
      dragMode: 'crop',
      aspectRatio: 16 / 9,
      preview: preview,
    }"
    @ready="ready"
  />
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import VuePictureCropper, { cropper } from 'vue-picture-cropper'

export default defineComponent({
  components: {
    VuePictureCropper
  },
  // …
})
</script>

上面是设定了一个裁剪区域,对于文件的选择/传入,以及裁切结果,请通过 <input type="file" >button 绑定实例的api来获取。

可参考 DEMO 里面的用法:

Props

简单的说明如下,可参考上方的用法示范自行调整。

props类型作用备注
boxStyleobject定义裁剪区域的样式,也就是包裹cropper的父级元素样式
imgstring要用来裁切的图片地址
optionsobject一些cropper的设定参数,完整可参考 options - cropperjs
eventsfunction一些cropper的回调函数,完整可参考 events - cropperjs
presetModeobject预设模式,可以开箱即用的预设效果0.4.0 版本才开始支持,详见下方的 预设模式 部分文档

btw: 远程图片会涉及到跨域问题,要服务端进行配合调整,请尽量使用本地图片来避免一些奇怪的问题出现。

常用选项

属性类型说明
viewModenumber可以决定裁切框的活动范围,可选 0、1、2、3,建议选 1 (裁切框只能在图片区域内活动)
aspectRationumber可以指定裁剪框的宽高比,不设置则为自由变化(建议按照裁切结果的尺寸设置对应的比例)
previewelement/string图片预览的容器,一个 DOM 元素。必须可以被 document.querySelectorAll 获取到

常用方法

可通过 cropper 实例来调取插件的各种 API (也就是在 import 的时候花括号里的那个实例)。

方法名功能说明用法示范备注
getDataURL获取裁切后的base64结果,可用于本地预览展示const dataURL = cropper.getDataURL()
getBlob获取裁切后的 blob 结果,可用于传给服务端const blob = cropper.getBlob()
getFile获取裁切后的 file 结果,可用于传给服务端const file = cropper.getFile()0.2.0 版本开始才支持该方法
clear清除裁切框cropper.clear()
reset重置默认的裁切区域cropper.reset()

需要注意的是

getDataURL 是同步方法,可以直接拿到结果。

getBlobgetFile0.3.0 版本开始是异步方法!!!需配合 Promiseasync / await 等方式来获取结果。

三者均属于插件自带的方法,生成的文件格式都是基于源图片的格式,仅支持处理本地图片,不支持远程图片。

其中均可传入选项来控制获取到的结果变化:

属性类型说明默认值
widthnumber设置裁切结果的宽度原图所截区域的大小
heightnumber设置裁切结果的高度原图所截区域的大小
minWidthnumber设置裁切结果的最小宽度0
minHeightnumber设置裁切结果的最小高度0
maxWidthnumber设置裁切结果的最大宽度无上限
maxHeightnumber设置裁切结果的最大高度无上限
fillColorstring设置裁剪结果的背景色,比如你想改变png透明区域的颜色transparent
imageSmoothingEnabledboolean是否让裁剪后的图片显得平滑true
imageSmoothingQualitystring图片平滑质量,可选low、medium、highlow
fileNamestring文件名,目前只有 getFile 会用到该参数,可不传cropped-当前时间戳.原文件后缀

用法示范:

// 设定裁切后指定尺寸为 400x250 ,通常可以为 banner 图裁切指定尺寸
const opt = {
  width: 400,
  height: 250
};

// 裁切后会按照该尺寸生成结果
const dataURL = cropper.getDataURL(opt);

如果是要获取 blob 和 file ,请记得用异步方法:

cropper.getBlob()
  .then((blob) => {
    console.log('blob', blob)
  })
// 或者是 await cropper.getBlob()

cropper.getFile()
  .then((file) => {
    console.log('file', file)
  })
// 或者是 await cropper.getFile()

具体在项目工程里的使用可以参考文档前面附的 DEMO 源码。

如果需要转换格式或者处理远程图片,请使用 getCroppedCanvas (需注意:这个方法存在部分异步操作,请留意用法说明)

预设模式

这里提供了一些常用的预设模式,方便在日常的业务场景里快速使用。

通过 presetMode 来指定启用哪个预设模式。

属性类型说明
modestringfixedSize=固定尺寸模式,round=圆形模式
widthnumber裁切区的宽度,需要大于0
heightnumber裁切区的高度,需要大于0

注意事项:

  • presetMode 只提供了一些简化的配置,比如你要获取圆形头像,就无需自己去处理很多额外的东西,但是一些该传入的 options ,还是需要在 options 指定,请留意对应的示范代码

  • 目前使用 presetMode 的情况下, “裁切区域” 和 “裁切结果” 都是一样大的,也就是说,这里指定的 widthheight,会覆盖 getDataURL 等获取结果 API 传入的 widthheight

  • 在指定 presetMode.widthpresetMode.height 的时候,请留意宽高比例是否与 aspectRatio 一致,如果不一致可能得不到你想要的结果

  • presetMode.mode 只接收文档里提及到的值,传入其他将不起作用

固定尺寸模式

可用固定裁切区域的大小,并且获得和裁切区域一样大的裁切结果(这种情况下你可以禁止用户修改裁切区域大小)。

在线 DEMO :fixedSize - vue-picture-cropper-demo

DEMO 源码:fixedSize.vue - vue-picture-cropper-demo

使用方法:

  • presetModemode 指定为 fixedSize
  • presetModewidthheight 指定为想要的尺寸
  • optionsdragMode 设置为 move 可以防止裁剪框被取消
  • optionscropBoxResizable 设置为 false 可以关闭裁剪区的大小调整功能
  • optionsaspectRatio 比例指定为 width / height 的比例
<template>
  <vue-picture-cropper
    :boxStyle="{
      width: '100%',
      height: '100%',
      backgroundColor: '#f8f8f8',
      margin: 'auto',
    }"
    :img="pic"
    :options="{
      viewMode: 1,
      dragMode: 'move',
      aspectRatio: 1,
      cropBoxResizable: false,
    }"
    :presetMode="{
      mode: 'fixedSize',
      width: 50,
      height: 50,
    }"
  />
</template>

圆形模式

如果你在用户头像等地方,需要裁切为圆形图片,可以使用该模式来帮助你获得一个圆形的 png 图。

它也是固定裁切区域的大小,并且获得和裁切区域一样大的裁切结果(这种情况下你可以禁止用户修改裁切区域大小)。

这个情况下,裁切结果固定是 png 图片(否则似乎没有什么裁圆形的意义…)。

在线 DEMO :round - vue-picture-cropper-demo

DEMO 源码:round.vue - vue-picture-cropper-demo

使用方法:

  • presetModemode 指定为 fixedSize
  • presetModewidthheight 指定为想要的尺寸,两个值需要一样
  • optionsdragMode 设置为 move 可以防止裁剪框被取消
  • optionscropBoxResizable 设置为 false 可以关闭裁剪区的大小调整功能
  • optionsaspectRatio 比例指定为 1
<template>
  <vue-picture-cropper
    :boxStyle="{
      width: '100%',
      height: '100%',
      backgroundColor: '#f8f8f8',
      margin: 'auto',
    }"
    :img="pic"
    :options="{
      viewMode: 1,
      dragMode: 'move',
      aspectRatio: 1,
      cropBoxResizable: false,
    }"
    :presetMode="{
      mode: 'round',
      width: 100,
      height: 100,
    }"
  />
</template>

其他说明

因为本插件是对做了一层组件化的实现,所以本组件也同步了 cropperjs 的所有 API ,均可通过 cropper.xxxx 来使用原来的 API 。

如果你需要更多高级功能,可以戳原文档参考使用 events - cropperjs