在vue3中使用vue-cropper完成头像裁剪上传图片功能

最终效果如下: vue3项目,使用了element-plus组件库,和vue-cropper头像上传插件,实现了一个头像组件 插件文档:www.npmjs.com/package/vue... 同时参考了文章:blog.csdn.net/m0_62317155...

vue-cropper一个奇怪的bug是,使用此插件就不能导入vue的h函数,否则无法正常工作。另外,vue-cropper没有ts类型声明,所以本头像组件的lang是js

本头像组件代码如下,可根据需要复制使用:

html 复制代码
<!-- 修改头像组件 -->
<script setup lang="js">
import Avatar from '@/assets/images/defaultAvatar.png'
import { useUserStore } from '@/stores'
import { ref, reactive, computed } from 'vue'
import { postUploadAvatar } from '@/api/user/index.ts' // 上传头像的api
// 头像图片截取合适尺寸后上传
import 'vue-cropper/dist/index.css'
import { VueCropper } from "vue-cropper"

const root = ref() // 本组件根元素,ElMessage渲染用
const userStore = useUserStore()
// 原本的头像
const originalAvatar = computed(() => {
  if (userStore.userInfo && userStore.userInfo.avatar) return userStore.userInfo.avatar
  else return Avatar
})
// 裁剪上传插件ref
const cropper = ref()
// 裁剪上传头像尺寸插件参数
const options = reactive({
  avatar: Avatar,
  outputType: 'jpg,jpeg,png',
  autoCrop: true,
  fixed: true,
  fixedNumber: [1, 1],
  canMove: false,
  centerBox: true
})
// 当上传图片多于1张时进行处理
const upload = ref()
const onExceed = (files) => {
  upload.value.clearFiles()
  const file = files[0]
  upload.value.handleStart(file)
}
// 是否在进行上传操作
const isUploading = ref(false)
// 当选中了图片要上传时
const onAvatarChange = (uploadObj) => {
  if (uploadObj.raw.size <= (1024 ** 2) * 10) {
    const fileReader = new FileReader()
    fileReader.onload = function (e) {
      options.avatar = e.target.result
    }
    fileReader.readAsDataURL(uploadObj.raw)
    isUploading.value = true
  } else {
    upload.value.clearFiles()
    ElMessage.error({ message: '上传图片大小不能超过10MB', appendTo: root.value })
  }
}
// 点击上传按钮,上传头像
const uploadAvatar = () => {
  // 调用插件的获取截图函数
  cropper.value.getCropBlob(async (data) => {
    try {
      const imgType = data.type.substring(6)
      const tempFile = new File([data], 'avatar.' + imgType, { type: data.type, lastModified: Date.now() })
      const responseUrl = await postUploadAvatar(tempFile)
      userStore.userInfo.avatar = responseUrl
      isUploading.value = false
      ElMessage.success({ message: '修改成功', appendTo: root.value })
    } catch (e) {
      ElMessage.error({ message: '上传失败', appendTo: root.value })
    }
  })
}
// 取消上传头像
const cancelUpload = () => {
  options.avatar = ''
  isUploading.value = false
}
</script>

<template>
  <div style="position: relative;" ref="root">
    <div v-if="!isUploading">
      <el-tooltip effect="light" content="点击上传头像" placement="top">
        <el-upload ref="upload" class="avatar-upload" accept=".jpeg,.jpg,.png" :limit="1" :auto-upload="false"
          :on-exceed="onExceed" :show-file-list="false" :on-change="onAvatarChange">
          <img class="avatar-img" :src="originalAvatar" alt="" @click="changeAvatar">
        </el-upload>
      </el-tooltip>
    </div>
    <div v-else>
      <VueCropper class="avatar-editing" ref="cropper" :img="options.avatar" :outputType="options.outputType"
        :autoCrop="options.autoCrop" :fixed="options.fixed" :fixedNumber="options.fixedNumber"
        :canMove="options.canMove" :centerBox="options.centerBox" />
      <span class="avatar-editing-span" @click="uploadAvatar">上传</span>
      <span class="avatar-editing-span" @click="cancelUpload">取消</span>
    </div>
  </div>
</template>

<style scoped lang="scss">
.avatar-img {
  display: inline-block;
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  margin-bottom: 5px;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  cursor: pointer;
}

.avatar-editing {
  display: inline-block;
  position: absolute;
  left: 50%;
  top: 0;
  transform: translateX(-50%);
  margin-bottom: 5px;
  width: 130px;
  height: 130px;
}

.avatar-editing-span {
  display: inline-block;
  position: absolute;
  left: 50%;
  top: 55px;
  transform: translateX(85px);
  color: #1764FF;
  cursor: pointer;

  &:last-child {
    transform: translateX(130px);
  }
}

:deep(.el-message) {
  transform: translateX(16px);
}
</style>
相关推荐
低保和光头哪个先来2 分钟前
源码篇 生命周期
前端·javascript·vue.js
持敬chijing3 分钟前
Web渗透之SQL注入-盲注(布尔盲注,时间盲注)
前端·sql·oracle
NGINX开源社区14 分钟前
NGINX Ingress Controller 中的 Cache Policy:VirtualServer 实战指南
java·前端·nginx
办公自动化软件定制化开发python23 分钟前
开源!Edge TTS 音频转换工具 v2.1:批量文本转语音,支持段落拆分与多发音人
前端·edge·音视频
276695829226 分钟前
jd 变速滑块逆向角度分析
前端·python·京东滑块·京东逆向·京东变速滑块·cfe滑块·wasm逆向
ct97829 分钟前
Vue 项目性能优化
前端·vue.js·性能优化
魔术师Grace40 分钟前
真正值钱的 AI 小工具,可能只是帮人少打一遍字
前端·人工智能
用户新4 小时前
JS事件深度解析四 事件的循环和异步
前端·javascript·事件·event loop
广州灵眸科技有限公司10 小时前
瑞芯微RV1126B开发板(EASY-EAI-PI2) Easy-Eai编译环境准备与更新
服务器·前端·人工智能·python·深度学习