自定义Taro上传图片hooks(useUploadImg)

有两个方法需要提前引入 FileUtil(上传文件的方法)、to(对请求接口返回做了二次处理,数据和错误提示等)

javascript 复制代码
//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 });
      }
    });
  };
}
javascript 复制代码
//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];
    });
}
javascript 复制代码
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,
  };
};

在页面中使用

javascript 复制代码
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>
})


相关推荐
竹秋…4 分钟前
el-table 滚动条小箭头点不了且部分滚动条无法拖动的问题
javascript·vue.js·elementui
做怪小疯子18 分钟前
JavaScript 中Array 整理
开发语言·前端·javascript
旭编18 分钟前
牛客周赛 Round 117
java·开发语言
六元七角八分24 分钟前
CSDN文章如何转出为PDF文件保存
开发语言·javascript·pdf
froginwe1132 分钟前
MongoDB 删除数据库
开发语言
Java小混子33 分钟前
golang项目CRUD示例
开发语言·后端·golang
香香爱编程35 分钟前
Electron里的electron-window-state 使用
前端·javascript·vue.js·vscode·electron·前端框架
涔溪36 分钟前
Vue 中实现 PDF 文件上传
javascript·vue.js·pdf
想搞艺术的程序员36 分钟前
Go 优雅关闭实践指南:从原理到框架落地
开发语言·后端·golang
JohnYan40 分钟前
Bun技术评估 - 29 Docker集成
javascript·后端·docker