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

发布时间:2023年12月22日

有两个方法需要提前引入 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>
})



在这里插入图片描述
在这里插入图片描述

文章来源:https://blog.csdn.net/qq_34574204/article/details/135146905
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。