文章目录
- 问题说明
- 使用说明
- 1.使用场景
- 2. 文件需要压缩
- 3. 使用技术
- 4. 代码如下
- 5. utils/index.js 代码
- 3. 总结说明
问题说明
- 只针对uniapp开发H5网页,使用uniapp api获取到的临时路径不能满足使用场景,其他平台未进行测试
使用说明
1.使用场景
使用uview-ui的u-upload组件上传图片
2. 文件需要压缩
我的业务场景是上传图片之后,需要使用ocr识别,文件太大的话,识别比较缓慢,所以需要进行压缩
3. 使用技术
// npm install compressorjs
import Compressor from 'compressorjs';
4. 代码如下
这是在u-upload组件的基础上进行封装的ImageUpload组件, 先获取到临时路径,通过fetch请求获取到blob对象,然后再进行转file处理,相应的处理函数是
tempFilePathToFile
,compressFile
<template><view class="upload-container"><u-upload :previewImage="true" :max-count="maxCount" :auto-upload="false" @afterRead="handleAfterRead"@beforeRead="handleBeforeRead" :useBeforeRead="true" @delete="handleDelete" :multiple="multiple":accept="accept" :fileList="fileList"><slot name="file"></slot></u-upload></view>
</template><script>
import { getToken, tempFilePathToFile, compressFile } from "@/utils";
import { uploadFile } from "@/utils/api";export default {data() {return {fileList: [// {// url: "/dev-api/profile/upload/2024/10/30/公司logo_20241030231031A009.jpg",// },],};},props: {value: [String, Object, Array],maxCount: {type: Number,default: 1,},// 文件大小限制 MfileSize: {type: Number,default: 20,},fileType: {type: Array,default: () => ["jpg", "png", "jpeg"],},accept: {type: String,default: "image",},multiple: {type: Boolean,default: false,},// 是否压缩的阈值 单位Mthreshold: {type: Number,default: 1,},},watch: {value: {handler(val) {if (val) {// 首先将值转为数组const list = Array.isArray(val)? val: this.value.split(",");// 然后将数组转为对象数组this.fileList = list.map((item) => {if (typeof item === "string") {let baseURL = this.globalVar.request.baseURL;if (item.indexOf(baseURL) === -1) {item = {name: baseURL + item,url: baseURL + item,};} else {item = { name: item, url: item };}}return item;});} else {this.fileList = [];return [];}},deep: true,immediate: true,},},methods: {// uploadFilePromise(url) {// return new Promise((resolve, reject) => {// uni.uploadFile({// url: `${this.globalVar.request.baseURL}/common/upload`, // 仅为示例,非真实的接口地址// filePath: url,// name: "file",// header: {// Authorization: "Bearer " + getToken(),// },// success: (res) => {// setTimeout(() => {// resolve(JSON.parse(res.data));// }, 1000);// },// });// });// },uploadFilePromise(file) {return new Promise(async (resolve, reject) => {try {let formData = new FormData();formData.append("file", file, file.name);fetch(`${this.globalVar.request.baseURL}/common/upload`, {method: "POST",headers: {Authorization: "Bearer " + getToken(),},body: formData,}).then((res) => res.json()).then((res) => {resolve(res);});} catch (error) {console.log(error);resolve(null);}});},handleBeforeRead(e) {let files = typeof e.file === "object" ? [e.file] : e.file;let isLimitSize = files.some((file) => file.size > this.fileSize * 1024 * 1024);if (isLimitSize) {this.$u.toast(`文件大小不能超过${this.fileSize}MB`);return false;}let isLimitType = files.some((file) => !this.fileType.includes(file.name.split(".").pop()));if (isLimitType) {this.$u.toast(`仅支持${this.fileType.join(",")}格式`);return false;}return true;},async handleAfterRead(e) {let files = typeof e.file === "object" ? [e.file] : e.file;files.map((item) => {this.fileList.push({...item,status: "uploading",message: "上传中",});});let start = 0;for (let i = 0; i < files.length; i++) {let item = files[i];let file = await tempFilePathToFile({tempFilePath: item.url,fileName: item.name,});// 判断是否需要压缩if (file.size > this.threshold * 1024 * 1024) {file = await compressFile(file, { quality: 0.2 });}let res = await this.uploadFilePromise(file);if (res.code == 200) {this.fileList.splice(start,1,Object.assign(item, {status: "success",message: "",url: this.globalVar.request.baseURL + res.fileName,}));} else {this.fileList.splice(start,1,Object.assign(item, {status: "error",message: "上传失败",}));}start++;}this.$emit("input", this.listToString(this.fileList));let list = this.fileList.map((item) => {item.url = item.url.replace(this.globalVar.request.baseURL, "");return item;});this.$emit("change", list);},handleDelete(e) {this[`fileList`].splice(e.index, 1);this.$emit("input", this.listToString(this.fileList));// this.$emit("change", this.fileList);},// 对象转成指定字符串分隔listToString(list, separator) {let strs = "";separator = separator || ",";for (let i in list) {if (list[i].url) {strs +=list[i].url.replace(this.globalVar.request.baseURL,"") + separator;}}return strs != "" ? strs.substr(0, strs.length - 1) : "";},},
};
</script><style scoped>
.upload-container {padding: 20px;
}.upload-btn {display: flex;align-items: center;justify-content: center;border: 1px dashed #d9d9d9;border-radius: 5px;padding: 20px;cursor: pointer;
}.upload-file {position: relative;margin-top: 10px;
}.upload-file image {border: 1px solid #d9d9d9;border-radius: 5px;
}.upload-file .u-icon {position: absolute;top: 5px;right: 5px;
}
</style>
5. utils/index.js 代码
import Compressor from 'compressorjs';export const getToken = () => uni.getStorageSync('token') || '';export const removeToken = () => uni.removeStorageSync('token');export const base64Encode = (str) => {// 将字符串转换为 UTF-8 编码的字节数组const utf8Bytes = new TextEncoder().encode(str);// 将字节数组转换为 Base64 字符串return btoa(String.fromCharCode.apply(null, utf8Bytes));
};export const base64Decode = (base64) => {// 将 Base64 字符串转换为字节数组const byteString = atob(base64);// 将字节数组转换为 UTF-8 字符串const bytes = new Uint8Array(byteString.length);for (let i = 0; i < byteString.length; i++) {bytes[i] = byteString.charCodeAt(i);}return new TextDecoder().decode(bytes);
};export const goPageByPath = (path, query = {}) => {if (!path) {throw new Error('缺少必须的path参数');}let queryLen = Object.keys(query).length;let queryStr = '';if (queryLen) {queryStr = Object.keys(query).map((key) => `${key}=${query[key]}`).join('&');queryStr = `?${queryStr}`;}uni.navigateTo({url: `${path}${queryStr}`});
};// 表单重置
export function resetForm(refName) {if (this.$refs[refName]) {this.$refs[refName].resetFields();}
}// 判断 是否是数字
export const isStrictNumber = (value) => {return typeof value === 'number' && !isNaN(value);
};// 获取文件的后缀名,不包含 .
export const getFileExt = (fileName) => {return fileName.split('.').pop();
};// 临时路径转file对象 针对h5端
export const tempFilePathToFile = ({tempFilePath, fileName}) => {if (!tempFilePath) {return Promise.resolve(null);}return new Promise(async (resolve, reject) => {try {const response = await fetch(tempFilePath);const blob = await response.blob();const mimeType = response.headers.get('content-type');const file = new File([blob], fileName, {type: mimeType});resolve(file);} catch (error) {resolve(null);}});
};// 压缩文件
export const compressFile = (file, options) => {return new Promise((resolve, reject) => {new Compressor(file, {...options,success(result) {resolve(result);},error(err) {reject(err);},});});
};
3. 总结说明
可能有更好的处理方式, 如果大家有更好的处理方式,可以在评论区,贴出代码,让播主也学习一下,学无止境