pnpm-vue3-ts:裁剪 / 上传裁剪 / 头像-商品图片处理-图片编辑 / vue-cropper

一、简介

Vue-Cropper 是一个基于 Vue.js 的轻量级图片裁剪组件,专为前端项目中的图片裁剪需求设计。它提供了丰富的功能和灵活的配置选项,支持多种图片格式输入和输出,适用于头像裁剪、商品图片处理、图片编辑等场景。

二、使用场景

用户头像上传:允许用户裁剪并上传符合要求的头像。

商品图片处理:电商平台中,用户可裁剪商品主图或详情图。

图片编辑工具:集成到图片编辑器中,提供基础裁剪功能。

三、集成 vue-cropper 插件

pnpm install vue-cropper@next

main.ts

import VueCropper from 'vue-cropper' // 图片裁剪

app.use(VueCropper) // 图片裁剪

四、封装组件

技术栈:pnpm、vue3、typescript、vue-cropper

<!-- 图片裁剪组件 -->
<template>
    <el-dialog
      title="提示"
      v-model="dialogVisible"
      width="80%"
      :before-close="handleClose">
      <div class="cropper-container">
        <input type="file" accept="image/*" @change="handleFileChange" />
        <vue-cropper
          ref="cropperRef"
          :img="option.img"
          :outputSize="option.outputSize"
          :outputType="option.outputType"
          :info="option.info"
          :canScale="option.canScale"
          :autoCrop="option.autoCrop"
          :autoCropWidth="option.autoCropWidth"
          :autoCropHeight="option.autoCropHeight"
          :fixed="option.fixed"
          :fixedNumber="option.fixedNumber"
          @realTime="realTime"
          @imgLoad="imgLoad"
          style="width: 100%; height: 400px;"
        ></vue-cropper>
        
        <!-- 控制按钮 -->
        <div class="btn-group">
          <button @click="startCrop">开始裁剪</button>
          <button @click="stopCrop">停止裁剪</button>
          <button @click="clearCrop">清除裁剪</button>
          <button @click="changeScale(1)">放大</button>
          <button @click="changeScale(-1)">缩小</button>
          <button @click="rotateLeft">左旋转</button>
          <button @click="rotateRight">右旋转</button>
          <button @click="getCropData">获取裁剪结果</button>
        </div>
        
        <!-- 实时预览 -->
        <div class="preview-box">
          <div class="preview" :style="previews.div">
            <img :src="previews.url" :style="previews.img">
          </div>
        </div>
      </div>
    </el-dialog>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue'
import image from '/m-general/assets/images/home.jpg'
const dialogVisible = ref(false) // 控制弹窗显示
const setDialogVisible = (val: boolean) => {
  dialogVisible.value = val
}
defineExpose({ // 暴露给父组件
  setDialogVisible
})
const handleClose = (done: Function) => {
  done()
}
const option:any = reactive({
  img: image,  // 裁剪图片的地址
  outputSize: 1,         // 裁剪生成图片的质量(0.1-1)
  outputType: 'jpeg',    // 裁剪生成图片的格式
  info: true,           // 显示裁剪框的大小信息
  canScale: true,       // 图片是否允许滚轮缩放
  autoCrop: true,       // 是否默认生成截图框
  autoCropWidth: 300,   // 默认生成截图框宽度
  autoCropHeight: 200,  // 默认生成截图框高度
  fixed: true,          // 是否开启截图框宽高固定比例
  fixedNumber: [3, 2],  // 截图框的宽高比例
})

let previews:any = reactive({
  url: image,  // 图片地址
  img: { // 裁剪后图片的样式
    width: '100%',
    height: '100%',
  },
})
// 处理文件选择
const handleFileChange = (e: Event) => {
  const file = (e.target as HTMLInputElement).files?.[0]
  if (!file) return
  
  // 检查文件类型
  if (!file.type.includes('image/')) {
    alert('请选择图片文件')
    return
  }
  
  // 创建URL
  const reader = new FileReader()
  reader.onload = (event) => {
    console.log('77-', event)
    option.img = event.target?.result as string
  }
  reader.readAsDataURL(file)
}
// 实时预览
const realTime = (data: any) => {
  console.log('84--图片加载:', data)
  previews.url = data.url
}
// 图片加载完成
const imgLoad = (msg: any) => {
  console.log('图片加载:', msg)
}
const cropperRef = ref<InstanceType<typeof VueCropper> | null>(null)
// 开始裁剪
const startCrop = () =>{
  if (!cropperRef.value) return
  cropperRef.value.startCrop()
}
// 停止裁剪
const stopCrop = () => {
  cropperRef.value.stopCrop()
}
// 清除裁剪
const clearCrop = () => {
  cropperRef.value.clearCrop()
}
// 缩放
const changeScale = (num: number) => {
  cropperRef.value.changeScale(num)
}
// 左旋转
const rotateLeft = () => {
  cropperRef.value.rotateLeft()
}
// 右旋转
const rotateRight = () => {
  cropperRef.value.rotateRight()
}
const emit = defineEmits([ // 定义事件
  'setImage'
])
// 获取裁剪结果
const getCropData = () => {
  // 获取base64数据
  cropperRef.value.getCropData((data: string) => {
    console.log('裁剪完成:', data)
    previews.url = data
    emit('setImage', data)
  })
}
</script>

<style scoped lang="scss">
.cropper-container {
  max-width: 800px;
  margin: 0 auto;
  .btn-group {
    margin: 20px 0;
    text-align: center;
  }
  
  .btn-group button {
    margin: 0 5px;
    padding: 8px 16px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
  
  .btn-group button:hover {
    background: #0056b3;
  }
  
  .preview-box {
    margin-top: 20px;
  }
  
  .preview {
    width: 200px;
    height: 133px;
    overflow: hidden;
    border: 1px solid #ccc;
    margin: 0 auto;
  }
}
</style>

五、父组件调用

<template>
    <el-button @click="btn">上传裁剪</el-button>
    <m-cropper ref="myCropperRef" @setImage="setImage"></m-cropper>
    <img :src="previews.url" :style="previews.img">
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
const myCropperRef = ref<InstanceType<typeof VueCropper> | null>(null)
const btn = async () => {
    console.log('8--', myCropperRef.value)
    myCropperRef.value.setDialogVisible(true)
}
let previews:any = reactive({
  url: '',  // 图片地址
  img: { // 裁剪后图片的样式
    width: '100px',
    height: '100px',
  },
})
const setImage = (val:any) => {
  console.log('24--', val)
  previews.url = val
}
</script>

<style scoped>
</style>

六、Vue-Cropper 部分核心配置项

配置项说明默认值可选值
img图片源,支持 URL、base64 或 blob 格式nullURL/base64/blob
outputSize输出图片质量10.1 - 1
outputType输出图片格式'jpeg''jpeg''png''webp'
autoCrop是否自动生成裁剪框falsetruefalse
autoCropWidth裁剪框宽度父容器的 80%数值
autoCropHeight裁剪框高度父容器的 80%数值
fixed是否固定宽高比truetruefalse
fixedNumber宽高比例[1, 1][width, height]
canScale是否允许缩放图片truetruefalse
canMove是否允许移动图片truetruefalse
canMoveBox是否允许移动裁剪框truetruefalse
fixedBox是否固定裁剪框大小falsetruefalse
mode图片渲染模式'contain''contain''cover' 等
enlarge输出放大倍数1数值
centerBox是否限制裁剪框在图片内falsetruefalse
info是否显示裁剪框的大小信息falsetruefalse
full是否输出原图比例截图falsetruefalse
original上传图片是否显示原始宽高falsetruefalse
maxImgSize限制图片最大尺寸,避免移动端内存问题数值(单位:像素)
enableExif是否自动处理 EXIF 方向信息(旧版浏览器)truetruefalse
high是否开启高清模式falsetruefalse
crossOrigin图片跨域属性null'Anonymous''Use-Credentials' 等
checkCrossOrigin是否检查跨域truetruefalse

七、Vue-Cropper 的部分核心事件

事件名说明触发时机
@realTime实时预览事件,在裁剪框移动或缩放时触发裁剪框位置或大小变化时
@imgLoad图片加载完成事件图片成功加载到裁剪组件后
@cropMove裁剪框移动事件裁剪框在图片上移动时
@cropMoving裁剪框移动中事件(持续触发)裁剪框移动过程中持续触发
@zoom图片缩放事件图片被缩放时
@crop裁剪完成事件(部分版本可能支持)裁剪操作完成时(需结合具体版本)
@mouseMove.native鼠标移动事件(需结合原生事件修饰符,非插件内置但常用)鼠标在裁剪区域移动时
@mouseUp.native鼠标释放事件(需结合原生事件修饰符,非插件内置但用于结束裁剪交互)鼠标在裁剪区域释放时

八、 欢迎交流指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值