自定义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>
})


相关推荐
JUNAI_Strive_ving4 分钟前
番茄小说逆向爬取
javascript·python
落落落sss8 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
看到请催我学习13 分钟前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
简单.is.good26 分钟前
【测试】接口测试与接口自动化
开发语言·python
twins352032 分钟前
解决Vue应用中遇到路由刷新后出现 404 错误
前端·javascript·vue.js
Yvemil71 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
qiyi.sky1 小时前
JavaWeb——Vue组件库Element(3/6):常见组件:Dialog对话框、Form表单(介绍、使用、实际效果)
前端·javascript·vue.js
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
哪 吒1 小时前
华为OD机试 - 几何平均值最大子数(Python/JS/C/C++ 2024 E卷 200分)
javascript·python·华为od