vue-advanced-cropper和腾讯云对象存储封装的头像上传组件

<template>
  <div class="corpping-warp">
    <!-- 显示头像-选择图片 -->
      <el-upload  action :on-change="selectImage" :show-file-list="false" accept=".jpg,.png" :auto-upload="false">
        <div class="avatar-warp">
          <el-avatar :size="110" :src="avatarUrl"></el-avatar>
          <span class="el-icon-edit"></span>
        </div>
      </el-upload>

    <el-dialog
      title="更换头像"
      v-model="dialogVisible"
      width="40%"
    >
      <!-- 图片裁剪 -->
      <Cropper ref="cropper" stencil-component="circle-stencil" class="cropper" :src="img" :debounce="false" @change="onChange"/>
      <!-- 预览图 -->
      <Preview class="cropper-preview" :image="result.image" :coordinates="result.coordinates"/>
      <template #footer>
        <span class="dialog-footer">
          <el-button  @click="dialogVisible = false">取 消</el-button>
          <DlButton label="确 定" @click="crop"></DlButton>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import DlButton from '@/components/common/DlButton'
import { ref, toRefs, watch } from 'vue'
import { cos, cosUpload } from '@/utils/cosUpload'
export default {
  components: { DlButton },
  props: {
    defaultAvatarUrl: {
      type: String,
      default: ''
    }
  },
  setup (props) {
    const { defaultAvatarUrl } = toRefs(props)
    const avatarUrl = ref('')
    watch(defaultAvatarUrl, (value, oldValue) => {
      avatarUrl.value = defaultAvatarUrl.value
    })

    return {
      avatarUrl
    }
  },
  data: function () {
    return {
      dialogVisible: false, // 对话框显示
      img: '', // 头像地址
      change: {
        coordinates: {}, // on-change的坐标
        image: null // on-change预览图
      },
      result: { // 确定的裁剪图
        coordinates: {},
        image: null
      },
      imageFile: null, // 原始文件
      avatarFile: { // 头像文件
        file_path: null,
        origin_file_name: null,
        file_mime_type: null,
        file_extension: null,
        file_size: null
      }
    }
  },
  methods: {
    // 选择裁剪图片
    selectImage (file) {
      console.log('选择的文件信息', file)
      this.imageFile = file.raw
      const preUrl = URL.createObjectURL(file.raw)
      this.img = preUrl
      this.dialogVisible = true
    },
    /* 确认截取部位 */
    crop () {
      const { canvas } = this.$refs.cropper.getResult()
      // 预览路径
      this.avatarUrl = canvas.toDataURL()

      // Blob对象
      canvas.toBlob(item => {
        item.name = this.imageFile.name
        cosUpload(item, cos, '/test/').then((res) => {
          this.avatarFile.file_path = res
          this.avatarFile.origin_file_name = this.imageFile.name
          this.avatarFile.file_mime_type = item.type
          this.avatarFile.file_extension = this.imageFile.name.split('.').pop().toLowerCase()
          this.avatarFile.file_size = item.size
          this.$emit('sendAvatar', this.avatarFile)
        })
      }, 'image/jpeg', 0.8)
      // console.log('结果路径', this.avatarUrl)
      this.dialogVisible = false
    },
    onChange ({ coordinates, image }) {
      this.result.coordinates = coordinates
      this.result.image = image
    }
  },
  emits: ['sendAvatar']
}
</script>

<style lang="scss" scoped>
.cropper {
  height: 500px;
  background: #DDD;
}
.corpping-warp :deep(.el-dialog){
  margin-top: 5vh !important;
}
.avatar-warp{
  width: 110px;
  height: 110px;
  overflow:hidden;
  border-radius: 50%;
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  span {
    position: absolute;
    top: 50%;
    left: 50%;
    color: #fff;
    transform: translate(-50%, -50%);
    font-size: 30px;
    cursor: pointer;
  }
  .el-icon-edit{
    opacity: 0;
    transition: all 0.3s;
  }
  &:hover{
    .el-icon-edit{
      opacity: 1;
    }
  }
}
.cropper-preview{
  width: 110px;
  height: 110px;
  overflow: hidden;
  margin: 20px auto;
  border-radius: 50%;
}
</style>

posted @ 2021-05-30 23:47  脉望  阅读(400)  评论(0编辑  收藏  举报