组件代码:

<template>
  <div>
    <Uploader
      :multiple="multiple"
      :max-count="maxCount"
      :preview-size="previewSize"
      v-model="fileList"
      accept="image/*"
      @click-upload="(e) => handleUpload(e)"
      @delete="deleteFile"
    ></Uploader>
  </div>
</template>

<script setup lang="ts">
import { Toast, Uploader } from 'vant';
import { ref, watch } from 'vue';

import { uploadImage } from '@/service/qualityInspectionOperations.ts';
import { dataURLtoFile } from './util.ts';

const emits = defineEmits(['changeUrl']);
const props = defineProps({
  multiple: {
    type: Boolean,
    default: false,
  },
  previewSize: {
    type: Number,
    default: 76,
  },
  maxSize: {
    type: Number,
    default: 1024,
  },
  maxCount: {
    type: Number,
    default: 1,
  },
  needCompressd: {
    type: Boolean,
    default: false,
  },
});

const fileList = ref([]);
const imgUrlList = ref([]);

const getBase64 = (filePath: string): Promise<string> => {
  return new Promise((resolve) => {
    const options = {
      filePath,
      format: 'base64',
    };
    // eslint-disable-next-line no-undef
    const base64Url = jme.file.getFileData(options);
    resolve(base64Url);
  });
};

const onUpload = async (file: Record<string, any>) => {
  const formData = new FormData();
  formData.append('file', file.file);
  const res = await uploadImage(formData);
  if (res.success && res.data) {
    fileList.value.push(file);
    imgUrlList.value.push(res.data);
  } else {
    Toast('上传失败');
  }
};

// 获取base64 调用上传
const getFileUrl = async (fileData) => {
  const fileName = fileData.name;
  const base64: string = await getBase64(fileData.path);
  const file = dataURLtoFile(base64, fileName);
  onUpload({ file, name: fileName, content: base64 });
};

const chooseFile = () => {
  const options = {
    count: props.maxCount,
    type: 'image',
    callback: (res: Record<string, any>[]) => {
      if (res?.length) {
        res.forEach((item) => {
          getFileUrl(item);
        });
      }
    },
  };
  // eslint-disable-next-line no-undef
  jme.file.chooseFile(options);
};

const handleUpload = (e) => {
  e.preventDefault();
  chooseFile();
};

const deleteFile = (_, { index }: { index: number }) => {
  imgUrlList.value.splice(index, 1);
};

watch(
  () => imgUrlList.value,
  (newVal) => {
    emits('changeUrl', newVal);
  },
  { deep: true }
);
</script>
<style lang="less" scoped>
:deep(.van-uploader__preview-delete--shadow) {
  width: 18px;
  height: 18px;
  border-radius: 0 0 0 18px;
}
:deep(.van-uploader__preview-delete-icon) {
  font-size: 16px;
}
</style>

utils代码:

/**
 * 将base64转换为Blob
 * @param {string} base64 - base64字符串
 * @return {Blob} Blob对象
 */
export function dataURItoBlob(dataURI: string) {
  const byteString = atob(dataURI.split(',')[1]);
  const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
  const ab = new ArrayBuffer(byteString.length);
  const ia = new Uint8Array(ab);
  // eslint-disable-next-line no-plusplus
  for (let i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }
  return new Blob([ab], { type: mimeString });
}

/**
 * 使用FormData将图片的base64字符串转换成File对象
 * @param {string} base64 - base64字符串
 * @param {string} filename - 文件名
 * @return {File} file对象
 */
export function dataURLtoFileWithFormData(base64: string, filename: string) {
  const formData = new FormData();
  formData.append('file', dataURItoBlob(base64), filename);
  return formData.get('file');
}

/**
 * 将图片的base64字符串转换成File对象
 * @param {string} base64 - base64字符串
 * @param {string} filename - 文件名
 * @return {File} file对象
 */
export function dataURLtoFile(base64: string, filename: string) {
  const arr = base64.split(',');
  const typeMatch = arr[0].match(/:(.*?);/);
  const mime = typeMatch[1];
  const bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  // eslint-disable-next-line no-plusplus
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
}

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐