vue+elementui+vueCropper裁剪上传图片背景颜色为黑色解决方案

复制代码
组件
<template>
  <div class="avatar-uploader">
    <!-- 头像展示 -->
    <div class="avatar-show">
      <img :src="avatarUrl" v-if="avatarUrl" class="avatar">
      <i class="el-icon-plus avatar-uploader-icon" v-else></i>
    </div>

    <!-- 上传按钮 -->
    <el-upload
        class="avatar-upload"
        action="#"
        :show-file-list="false"
        :before-upload="beforeAvatarUpload"
        :http-request="handleUpload"
    >
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过2MB</div>
    </el-upload>

    <!-- 裁剪对话框 -->
    <el-dialog title="裁剪头像" :visible.sync="dialogVisible" width="800px">
      <div class="cropper-content">
        <div class="cropper">
          <vue-cropper
              ref="cropper"
              :img="cropperImg"
              :output-size="1"
              :output-type="'png'"
              :info="true"
              :full="true"
              :can-move="true"
              :can-move-box="true"
              :fixed="true"
              :fixed-number="[1, 1]"
              :center-box="true"
              :auto-crop="true"
              :auto-crop-width="200"
              :auto-crop-height="200"
          ></vue-cropper>
        </div>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="handleCrop">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { VueCropper } from 'vue-cropper'

export default {
  components: {
    VueCropper
  },
  props: {
    value: String // 用于v-model绑定
  },
  data() {
    return {
      dialogVisible: false,
      cropperImg: '', // 裁剪图片的base64
      // avatarUrl: this.value || require('@/assets/logo.png') // 默认头像
      avatarUrl: null // 默认头像
    }
  },
  methods: {
    // 上传前校验
    beforeAvatarUpload(file) {
      const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'
      const isLt2M = file.size / 1024 / 1024 < 2

      if (!isJPG) {
        this.$message.error('上传头像图片只能是 JPG/PNG 格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
      }
      return isJPG && isLt2M
    },

    // 处理上传
    handleUpload(file) {
      const reader = new FileReader()
      reader.onload = (event) => {
        this.cropperImg = event.target.result
        this.dialogVisible = true
        this.$nextTick(() => {
          this.$refs.cropper.replace(event.target.result)
        })
      }
      reader.readAsDataURL(file.file)
    },

    // 处理裁剪
    handleCrop() {
      this.$refs.cropper.getCropBlob((blob) => {
        // 创建FormData对象上传
        const formData = new FormData()
        formData.append('file', blob, 'avatar.png')
        // 这里替换为你的上传API
        this.$axios.post('/api/upload/avatar', formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        }).then(response => {
          this.avatarUrl = response.data.url
          this.$emit('input', this.avatarUrl) // 更新v-model
          this.dialogVisible = false
          this.$message.success('头像上传成功!')
        }).catch(error => {
          this.$message.error('头像上传失败!')
          console.error(error)
        })
      })
    },

    // 也可以使用base64格式
    handleCropBase64() {
      this.$refs.cropper.getCropData((data) => {
        this.avatarUrl = data
        this.$emit('input', data) // 更新v-model
        this.dialogVisible = false
        this.$message.success('头像裁剪成功!')
      })
    }
  },
  watch: {
    value(newVal) {
      this.avatarUrl = newVal
    }
  }
}
</script>

<style scoped>
.avatar-uploader {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.avatar-show {
  width: 150px;
  height: 150px;
  border: 1px dashed #d9d9d9;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 20px;
}

.avatar {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
}

.cropper-content {
  display: flex;
  justify-content: center;
}

.cropper {
  width: 500px;
  height: 500px;
}

.el-upload__tip {
  margin-top: 10px;
  text-align: center;
}
</style>

组件调用

<template>

<div>

<h2>个人头像设置</h2>

<avatar-uploader v-model="avatar"></avatar-uploader>

</div>

</template>

<script>

import AvatarUploader from '@/components/AvatarUploader'

export default {

components: {

AvatarUploader

},

data() {

return {

avatar: '' // 初始头像地址

}

}

}

</script>

注意一定要配置:output-type="'png'"

相关推荐
再学一点就睡2 小时前
手写 Promise 静态方法:从原理到实现
前端·javascript·面试
再学一点就睡3 小时前
前端必会:Promise 全解析,从原理到实战
前端·javascript·面试
90后的晨仔4 小时前
理解 Vue 的列表渲染:从传统 DOM 到响应式世界的演进
前端·vue.js
OEC小胖胖4 小时前
性能优化(一):时间分片(Time Slicing):让你的应用在高负载下“永不卡顿”的秘密
前端·javascript·性能优化·web
小小李程序员5 小时前
JSON.parse解析大整数踩坑
开发语言·javascript·json
宋辰月5 小时前
Vue2-VueRouter
开发语言·前端·javascript
haaaaaaarry6 小时前
Element Plus常见基础组件(一)
java·前端·javascript·vue.js
萌萌哒草头将军6 小时前
Prisma ORM 又双叒叕发布新版本了!🚀🚀🚀
前端·javascript·node.js
mldong7 小时前
推荐一款超高颜值的后台管理模板!Art-Design-Pro!开源!免费!
前端·vue.js·架构
我是ed.7 小时前
cocos Js 使用 webview 通过 postMessage 进行通信
开发语言·javascript·ecmascript