有两个方法需要提前引入 FileUtil(上传文件的方法)、to(对请求接口返回做了二次处理,数据和错误提示等)
//FileUtil
export namespace FileUtil {
const env = {
timeout: 10000,
uploadImageUrl: "阿里云的地址",
};
const genPolicy = () => {
let date = new Date();
date.setHours(date.getHours() + env.timeout);
let srcT = date.toISOString();
const policyText = {
expiration: srcT,
conditions: [
["content-length-range", 0, 1 * 1024 * 1024 * 1024], // 设置上传文件的大小限制1G
],
};
var rawStr = JSON.stringify(policyText);
var wordArray = Utf8.parse(rawStr);
var policyBase64 = Base64.stringify(wordArray);
return policyBase64;
};
const genSignature = (policyBase64, accessKey) => {
const byte = HmacSHA1(policyBase64, accessKey);
const signature = Base64.stringify(byte);
return signature;
};
export const upload = async (
fileInfo
): Promise<{ url: string; errMsg: string }> => {
const { path } = fileInfo;
return new Promise(async (resolve) => {
const res = await httpRequest({
url: "图片上传的接口",
method: "POST",
});
if (res?.code === 200 && res?.data) {
const {
Credentials: { AccessKeyId, AccessKeySecret, SecurityToken },
} = res.data;
const aliyunFileKey =
"mini_" + new Date().getTime() + path.split("tmp/")[1]; //文件命名
const policyBase64 = genPolicy();
const signature = genSignature(policyBase64, AccessKeySecret);
//小程序直传oss
Taro.uploadFile({
url: env.uploadImageUrl,
filePath: path,
name: "file",
header: {
"Content-Type": "multipart/form-data",
},
formData: {
key: aliyunFileKey,
policy: policyBase64,
OSSAccessKeyId: AccessKeyId,
signature: signature,
"x-oss-security-token": SecurityToken, //使用STS签名时必传。
success_action_status: "200",
},
success: function (resp) {
if (resp?.statusCode === 200) {
resolve({
url: env.uploadImageUrl + aliyunFileKey,
errMsg: "ok",
});
} else {
resolve({ url: "", errMsg: resp?.errMsg });
}
},
fail: function (err: any) {
resolve({ url: "", errMsg: err });
},
});
} else {
resolve({ url: "", errMsg: res?.msg });
}
});
};
}
//to
export async function to<T>(promise: Promise<T>): Promise<[Error | null, T]> {
if (!promise || !Promise.prototype.isPrototypeOf(promise)) {
// @ts-ignore
return await new Promise((resolve, reject) => {
reject(new Error("request promises as ths param"));
}).catch((error) => {
return [error, null];
});
}
// @ts-ignore
return await promise
.then(function () {
// @ts-ignore
return [null, ...arguments];
})
.catch((error) => {
return [error, null];
});
}
import { useState } from "react";
import { FileUtil, to } from "@/utils";
import Taro from "@tarojs/taro";
import { useLoading } from "taro-hooks";
interface UseUploadImgProps {
maxLength?: number;
initList?: string[];
}
export const useUploadImg = ({
maxLength = 9,
initList = [],
}: UseUploadImgProps) => {
const [fileList, setFileList] = useState<string[]>([...initList || []]);
const [showLoading, hideLoading] = useLoading({
title: "上传中...",
mask: true,
});
const handleUpload: (
path: any
) => Promise<{ url: string; errMsg: string }> = async (path) => {
return FileUtil.upload({ path });
};
const handleSendImage = async () => {
// 选择图片
const chooseImgResp = await to(
Taro.chooseImage({
count: maxLength - fileList?.length,
sizeType: ["original"],
sourceType: ["album", "camera"],
})
);
if (chooseImgResp[0]) {
return;
}
if (chooseImgResp[1].errMsg !== "chooseImage:ok") {
return;
}
const filesLen = chooseImgResp[1].tempFilePaths?.length;
let asyncArr: Promise<{ url: string; errMsg: string }>[] = [];
for (let i = 0; i < filesLen; i++) {
asyncArr.push(handleUpload(chooseImgResp[1].tempFilePaths[i]));
// 获取图片信息
}
showLoading().then();
Promise.all(asyncArr)
.then((res) => {
const upLoadList = res.filter(obj => obj.url !== '').map(item=>item.url);
setFileList((val) => [...val, ...upLoadList]);
})
.catch(() => {
Taro.showToast({ title: "上传失败,请重试", icon: "none" });
})
.finally(() => {
hideLoading().then();
});
};
return {
handleSendImage,
fileList,
setFileList,
};
};
在页面中使用
import { useUploadImg } from "定义hook的文件地址";
import Taro, { showToast } from "@tarojs/taro";
import { Image, View } from "@tarojs/components";
export const UpLoadImg = () => {
const { handleSendImage, fileList, setFileList } = useUploadImg({
maxLength,
}); // 这里就是useUploadImg 输出的方法和上传文件的list
<View>
{fileList.map((item, index) => (
<View key={item}>
<Image
src={item}
onClick={() => {
if (fileList) {
Taro.previewImage({
urls: fileList,
current: item,
});
}
}}
/>
<Image
src={iconDelete}
className={styles.imgDelete}
onClick={() => {
fileList.splice(index, 1);
setFileList(() => [...fileList]);
}}
/>
</View>
))}
{fileList.length < maxLength && (
<View onClick={() => handleSendImage()}>
<Image />
</View>
)}
</View>
})