组件代码:
<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 });
}