上传图片:

当前位置:   article > 正文

canvas头像裁剪上传插件cropperjs_canvas配合裁剪插件实现裁剪并上传

canvas配合裁剪插件实现裁剪并上传
<template>
  <div class="hello">
    <div class="avator">
      <div class="fileUPLoad" style="display: flex; align-items: center">
        <p class="crop-dialog-label" style="width: 90px">上传图片:</p>
        <a-upload
          name="avatar"
          list-type="picture-card"
          class="avatar-uploader"
          :show-upload-list="false"
          :before-upload="beforeUpload"
          @change="handleChange"
        >
          <span class="selectBtn">选择图片</span>
        </a-upload>
      </div>
      <p class="crop-dialog-limit-info">
        图片格式只支持:BMP、JPEG、JPG、PNG, 大小不超过2M
      </p>
      <div class="showing">
        <div class="img">
          <img ref="image" :src="picUrl" alt="请上传头像" />
        </div>
        <div class="res" style="margin-left: 60px">
          <p>头像预览</p>
          <div class="before"></div>
          <div class="before round"></div>
        </div>
      </div>
    </div>
    <a-button @click="sureSava">裁剪</a-button>
  </div>
</template>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
<script lang="ts">
import {
  defineComponent,
  onMounted,
  ref,
  useStore,
} from '@nuxtjs/composition-api'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import { message } from 'ant-design-vue'
import { uploadFile } from '~/api/file'
import useAxios from '~/hooks/useAxios'
import { postUpdateUserInfo } from '~/api/user'
import { FullState } from '~/store/types'
interface fileObj {
  lastModified: number
  name: string
  size: number
  type: string
  uid: string
  webkitRelativePath: string
  originFileObj: File
  percent: number
  response: string
  status: string
}
interface uploadDone {
  fileFullName: string
  staticDomain: string
}
function getBase64(img: any, callback: any) {
  const reader = new FileReader()
  reader.addEventListener('load', () => callback(reader.result))
  reader.readAsDataURL(img)
}

export default defineComponent({
  name: 'HelloWorld',
  setup() {
    const myCropper = ref<any>()
    const afterImg = ref<any>('')
    const image = ref<any>()

    const init = () => {
      myCropper.value = new Cropper(image.value, {
        autoCropArea: 0.8, // 可设置裁剪框的范围,为1则是与整个裁剪区域一样大
        dragMode: 'none',
        initialAspectRatio: 1,
        aspectRatio: 1,
        preview: '.before',
        background: false,
        zoomOnWheel: true,
        viewMode: 1,
      })
    }
    // 裁剪
    const sureSava = () => {
    // 裁剪之后的图片
      afterImg.value = myCropper.value
        .getCroppedCanvas({
          imageSmoothingQuality: 'high',
        })
        .toDataURL(imgInfo.type)
    }

    onMounted(() => {
    // 初始化画布不能放在 beforeUpload  方法中,因为upload上传图片时会多次调用,就会造成初始化多个画布,页面也显示多个
      init()
    })
    const store = useStore<FullState>()
    const $axios = useAxios()
    const picUrl = ref<string>('')
    let imgInfo: File
    const handleChange = (info: any) => {
      if (standard) {
        imgInfo = info.file.originFileObj
        getBase64(info.file.originFileObj, (imageUrl: any) => {
          picUrl.value = imageUrl
        })
        // 更新cavas画布上的图片
        myCropper.value.replace(picUrl.value)
      }
    }
    // 图片是否符合要求
    let standard = false
    const beforeUpload = (file: fileObj) => {
      const isJpgOrPng =
        file.type === 'image/jpeg' ||
        file.type === 'image/png' ||
        file.type === 'image/jpg' ||
        file.type === 'image/bmp'
      if (!isJpgOrPng) {
        message.error('请重新选择图片格式')
      }
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isLt2M) {
        message.error('图片过大!')
      }
      return (standard = isJpgOrPng && isLt2M)
    }
    const uploadImg = () => {
      try {
        const formdata = new FormData()
        formdata.append('appId', 'aiKnowledge')
        formdata.append('businessType', '')
        formdata.append('type', 'avatar')
        formdata.append('fileName', imgInfo.name)
        // ===裁剪后file对象向后台传递的第一种方法
        //   function data2blob(data: string, mime: string) {
        //   data = data.split(',')[1]
        //   data = window.atob(data)
        //   const ia = new Uint8Array(data.length)
        //   for (let i = 0; i < data.length; i++) {
        //     ia[i] = data.charCodeAt(i)
        //   }
        //   // canvas.toDataURL 返回的默认格式就是 image/png
        //   return new Blob([ia], {
        //     type: mime,
        //   })
        // }
        // formdata.append(
        //   'file',
        //   data2blob(afterImg.value, imgInfo.type),
        //   imgInfo.name
        // )
        // ===裁剪后file对象向后台传递的第二种方法   接口必须写在myCropper.value.getCroppedCanvas().toBlob() 函数体内 JS 执行机制会先调接口 后执行此函数 这样接口就缺失file参数  
        myCropper.value.getCroppedCanvas().toBlob(async (blob: Blob) => {
        // 必须传递第三个参数(上传文件的名字),否则file参数会有误 导致接口调不通
          formdata.append('file', blob, imgInfo.name)
          const res: uploadDone = await uploadFile($axios, formdata)
          const params = {
            appId: 'aiKnowledge',
            avatarUrl: res.staticDomain + '/' + res.fileFullName,
          }
          await postUpdateUserInfo($axios, params)
          store.commit('user/UPDATE_AVATAR', params.avatarUrl)
         myCropper()
        })
      } catch (error) {}
    }
    const handleCancel = () => {
      picUrl.value = ''
      // 关闭弹框注销画布
      myCropper.value.destroy()
    }
    return {
      image,
      afterImg,
      sureSava,
      handleChange,
      uploadImg,
      beforeUpload,
      picUrl,
      handleCancel,
    }
  },
})
</script>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
<style lang="less" scoped>
/deep/span.ant-upload:hover {
  background-color: #1f71e0;
  .selectBtn {
    color: #fff;
  }
}
.avator {
  margin-bottom: 16px;
  .showing {
    display: flex;
    .img {
      width: 280px;
      height: 280px;
      background-color: #ccc;
      img {
        width: 100%;
        height: 100%;
      }
    }
    .before {
      background-color: #ccc;
      width: 80px !important;
      height: 80px !important;
      overflow: hidden;
      img {
        width: 80px !important;
        height: 80px !important;
        border-radius: 4px;
      }
    }
    .round {
      margin-top: 30px;
      border-radius: 50%;
      img {
        border-radius: 50%;
      }
    }
  }
}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签