基于vue-picture-cropper二次封装的图片上传裁切组件

822 阅读1分钟
1.安装
npm install vue-picture-cropper
```js
<template>
  <div :disabled="isshow">
    <el-upload
      class="avatar-uploader"
      accept="image/png, image/jpeg"
      :show-file-list="false"
      :on-change="onChange"
      :auto-upload="Boolean(false)"
      :http-request="UploadLogo"
    >
      <img
        v-if="imageUrl"
        :src="
          imageUrl
            ? imageUrl.indexOf('blob') !== -1
              ? imageUrl
              : `${imageUrl}?x-oss-process=image/resize,w_128/quality,q_80`
            : ''
        "
        class="logo"
      />
      <el-icon v-else class="logo-uploader-icon">
        <Plus />
      </el-icon>
    </el-upload>
    <el-dialog v-model="addDialogVisible" destroy-on-close>
      <template #header="{ close, titleId, titleClass }">
        <div class="my-header">
          <h4 :id="titleId" :class="titleClass">图片裁切</h4>
          <el-button type="" @click="close">
            <!-- <el-icon class="el-icon--left"></el-icon> -->
            取消
          </el-button>
          <el-button type="" @click="clear">
            <!-- <el-icon class="el-icon--left"></el-icon> -->
            清除
          </el-button>
          <el-button type="" @click="reset">
            <!-- <el-icon class="el-icon--left"></el-icon> -->
            重置
          </el-button>
          <el-button type="primary" @click="getResult">
            <!-- <el-icon class="el-icon--left"></el-icon> -->
            裁切
          </el-button>
        </div>
      </template>
      <VuePictureCropper
        :boxStyle="{
          width: '100%',
          height: '100%',
          backgroundColor: '#f8f8f8',
          margin: 'auto'
        }"
        :img="cropperImageUrl"
        :options="options"
        @ready="ready"
      />
    </el-dialog>
  </div>
</template>

<script setup>
import { upload } from '@/api/upload.js'
import { blobToFile, dataURLtoBlob, base64toFile } from '@/component/cropper/photo.js'
import VuePictureCropper, { cropper } from 'vue-picture-cropper'
import { Picture, Download, Share, UploadFilled, Plus } from '@element-plus/icons-vue'
let { elMessage } = useElement()
let Form = ref('')
let imageUrl = ref('')

//groupID为后端规定好的携带的参数,可自行去掉
const props = defineProps({
  groupId: { type: String, default: '' },
  imgUrl: { type: String, default: '' },
  dataForm: { type: Object, default: () => ({}) },
  show: { type: Boolean, default: false },
  proportion: { type: Number, default: Number(16 / 9) }
})
const options = computed(() => {
  return {
    viewMode: 1,
    dragMode: 'crop',
    aspectRatio:props['proportion']
  }
})
console.log()

console.log(options)
const emits = defineEmits(['update:imageUrl'])

const isshow = ref(false)
isshow.value = props['show']
imageUrl.value = props['imgUrl']
Form.value = props['dataForm']
// watch props变化
watch(
  () => props.show,
  (newValue, oldValue) => {
    isshow.value = newValue
  }
)
watch(
  () => props.dataForm,
  (newValue, oldValue) => {
    Form.value = newValue
  }
)
watch(
  () => props.imgUrl,
  (newValue, oldValue) => {
    console.log(newValue)
    imageUrl.value = newValue
  }
)

//图片上传方法
const UploadLogo = async (file) => {
  if (file.size / 1024 / 1024 > 2) {
    elMessage('图片大小不得超过2MB', 'error')
    return false
  } else {
    //图片裁切
    addDialogVisible.value = true
  }
}
//图片压缩\
const addDialogVisible = ref(false)
const cropperImageUrl = ref('')
const imgQuality = 0.7
const beforeLogoUpload = (rawFile) => {
  if (rawFile.size / 1024 / 1024 > 2) {
    elMessage('图片大小不得超过2MB', 'error')
    return false
  } else {
    //图片裁切
    addDialogVisible.value = true
//图片上传监听
const upload_file = ref({})
const onChange = (uploadFile) => {
  upload_file.value = uploadFile
  addDialogVisible.value = true
  cropperImageUrl.value = URL.createObjectURL(uploadFile.raw)
}
//图片裁切方法
const clear = () => {
  if (!cropper) return
  cropper.clear()
}
const reset = () => {
  if (!cropper) return
  cropper.reset()
}

const getResult = async () => {
  if (!cropper) return
  const base64 = cropper.getDataURL()
  const blob = await cropper.getBlob()
  if (!blob) return
  //用formData 提交
  let formData = new FormData()

  if (upload_file) {
    formData.append('file', blob)
    formData.append('group_id', props['groupId'])
  }
  try {
    let res = await upload(formData)
    if (res.code == 20000) {
      elMessage('上传成功')
      imageUrl.value = URL.createObjectURL(blob)
      Form.value = Object.assign(Form.value, { cover_id: res.data.id })
      addDialogVisible.value = false
    }
  } catch (err) {
    console.log(err)
  }
}
</script>

<style lang="scss" scoped>
.logo {
  width: 128px;
  height: 128px;
  display: block;
  object-fit: contain;
}

.logo-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.logo-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.logo-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 128px;
  height: 128px;
  text-align: center;
  border: 1px dashed #8c939d;
}

.avatar {
  width: 128px;
}
</style>