vueCropper裁剪之后图片转化成file二进制数据流

封装裁剪图片的组件

<template>
  <!-- 裁剪 -->
  <el-dialog
    v-model="imgUpload.dialogCropping"
    custom-class="dialog_custom"
    title="裁剪图片"
    append-to-body
    :close-on-press-escape="false"
    :show-close="false"
    :close-on-click-modal="false"
  >
    <div>
      <div class="h-96 w-full" style="height: 500px">
        <vueCropper
          ref="cropperRef"
          class="vue_cropper_custom"
          :img="imgCropping.imageUrl"
          :outputType="imgCropping.outputType"
          :autoCrop="imgCropping.autoCrop"
          :autoCropWidth="imgCropping.autoCropWidth"
          :autoCropHeight="imgCropping.autoCropHeight"
          :fixed="imgCropping.fixed"
          :fixedNumber="imgCropping.fixedNumber"
          :centerBox="imgCropping.centerBox"
          :full="imgCropping.full"
        ></vueCropper>
      </div>
    </div>
    <template #footer>
      <el-button v-focus @click="handleCropping(false)"> 取消 </el-button>
      <el-button type="primary" @click="handleCropping(true)"> 确定 </el-button>
    </template>
  </el-dialog>
</template>
<script setup>
import { reactive, defineEmits, ref } from "vue";
import { ElMessage } from "element-plus";

const cropperRef = ref(null);
const emit = defineEmits(["imgUpload"]);
const imgCropping = reactive({
  imageUrl: "",
  // 裁剪生成图片的格式
  outputType: "png",
  // 是否默认生成截图框
  autoCrop: true,
  // 上传图片按照原始比例渲染
  //   original: true,
  // 是否输出原图比例的截图
  full: false,
  // 默认生成截图框宽度
  autoCropWidth: 160,
  // 默认生成截图框高度
  autoCropHeight: 90,
  // 是否开启截图框宽高固定比例
  fixed: true,
  // 截图框的宽高比例
  fixedNumber: [16, 9],
  // 截图框是否被限制在图片里面
  centerBox: true,
});

/** 图片上传 */
const imgUpload = reactive({
  // 是否展示裁剪
  dialogCropping: false,
  isCropping: false, // 判断是否已经截图
  // 图片
  imageUrl: "",
  rawFile: {},
  // 图片格式
  imgBmp: "image/*",
  // 图片名称
  imgName: "",
});
const openDialog = (bool, rawFile) => {
  console.log(rawFile, "rawFilerawFile");
  // 进入裁剪
  // 图片名称
  imgUpload.imgName = rawFile.name;
  imgCropping.imageUrl = URL.createObjectURL(rawFile);
  imgUpload.dialogCropping = bool;
  imgUpload.rawFile = rawFile;
};

// base64转file
const base64ToFile = (base64, filename = "") => {
  const arr = base64.split(",");
  let mime = arr[0].match(/:(.*?);/)[1]; // 匹配出图片类型
  mime = mime.replace("data:", ""); // 去掉data:image/png;base64 // 去掉url中的base64,并转化为Uint8Array类型
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
};
// 生成裁剪图片
//还有一种getCropBlob转换成blob格式的
const handleCropping = (type) => {
  if (type) {
    cropperRef.value.getCropData((data) => {
      //此时data就是base64格式
      // base64转换成二进制格式File
      let  rawFileAvatar = base64ToFile(data, "avatar.png")
      //imgUpload.imageUrl【blob:http://localhost/c653d7c0-cdbe-42e2-9748-48c97350b871】让图片复显的
      imgUpload.imageUrl = URL.createObjectURL(rawFileAvatar);
      imgUpload.dialogCropping = false;
      // 图片信息
      emit(
        "img-upload",
        rawFileAvatar,
        imgUpload.imageUrl,
        imgUpload.imgName
      );
    });
  } else {
    imgUpload.imageUrl = "";
    imgUpload.dialogCropping = false;
  }
};
// 清除图片
const clearImg = () => {
  imgUpload.imageUrl = "";
  //   emit("img-upload");
};
defineExpose({ openDialog });
</script>

//父组件

template
   <el-upload
                :class="{ isShowImg:PictureList.value.length > 0 }"
                action="#"
                list-type="picture-card"
                :auto-upload="false"
                :limit="1"
                :on-exceed="handleExceed"
                v-model:file-list="PictureList.valuet"
                :on-change="handleChange"
              >
                <el-icon>
                  <Plus />
                </el-icon>
                <template #file="{ file }">
                  <div>
                    <img
                      class="el-upload-list__item-thumbnail"
                      :src="file.url"
                      alt=""
                    />
                    <span class="el-upload-list__item-actions">
                      <span
                        v-if="!disabled"
                        class="el-upload-list__item-delete"
                        @click="handleRemovePicture(file)"
                      >
                        <el-icon>
                          <Delete />
                        </el-icon>
                      </span>
                    </span>
                  </div>
                </template>
              </el-upload>
               <Cropper ref="cropperRef" @imgUpload="imgUpload" />
              
<script setup>
const   cropperRef = ref(null)

图片上传的change方法:
const handleChange = (data, fileList) => {
  let file = data.raw;
  const isJpgPng =
    file.type === "image/jpeg" ||
    file.type === "image/png" ||
    file.type === "image/gif";

  if (!isJpgPng) {
    ElMessage({ message: "上传文件格式只能是jpg/png/gif", type: "warning" });
    const currIdx = fileList.indexOf(file);
    fileList.splice(currIdx, 1);
    return false;
  }

  const isLt2M = file.size / 1024 / 1024 < 2;
  if (!isLt2M) {
    ElMessage({ message: "上传头像图片大小不能超过 2MB!", type: "warning" });
    const currIdx = fileList.indexOf(file);
    fileList.splice(currIdx, 1);
    return false;
  }
  const isSize = new Promise(function (resolve, reject) {
    const img = new Image();
    img.onload = function () {
      const valid = img.width / img.height === 16 / 9;
      valid ? resolve() : reject();
    };
    img.src = URL.createObjectURL(file);
    // selectedImageUrl.value = URL.createObjectURL(file);
    console.log(selectedImageUrl.value, "selectedImageUrl");
  }).then(
    () => {
      return file;
    },
    () => {
      ElMessage({
        message: "上传图片比例只能为16:9, 请进行裁剪!",
        type: "warning",
      });

      const currIdx = PictureList.value.indexOf(file);
     PictureList.value.splice(currIdx, 1);
      cropperRef.value.openDialog(true, file);
      // return Promise.reject();
      return false;
    }
  );
  if (fileList.length > 0) {
    isImgUploadRef.value.clearValidate();
  }
  return isJpgPng && isLt2M && isSize;
};


const imgUpload = (data, blob, name) => {
  const formData = new FormData();
  formData.append("file", data);
  console.log(formData);
  PictureList.value.push({
    name: name,
    url: blob,
    data: data,
    type: "封面",
    // response: {
    //   data: res.data,
    // },
  });
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值