项目背景:react+umi+antdesign
公司原本封装了一套上传,上传过程中损坏了.p9格式图片的信息。
后经过oss-brower客户端上传图片后验证直传是没有损坏文件信息的。
然后封装了如下组件。
- 引入ali-oss
npm i ali-oss
- 新建文件夹ossUpload封装上传组件,文件夹下新建guid.js index.js index.tsx.
- guid.js内容可直接复制
// 这里是上边中引用的guid文件 function GUID() { this.date = new Date(); /* 判断是否初始化过,如果初始化过以下代码,则以下代码将不再执行,实际中只执行一次 */ if (typeof this.newGUID != 'function') { /* 生成GUID码 */ GUID.prototype.newGUID = function () { this.date = new Date(); var guidStr = '', sexadecimalDate = this.hexadecimal(this.getGUIDDate(), 16), sexadecimalTime = this.hexadecimal(this.getGUIDTime(), 16); for (var i = 0; i < 9; i++) { guidStr += Math.floor(Math.random() * 16).toString(16); } guidStr += sexadecimalDate; guidStr += sexadecimalTime; while (guidStr.length < 32) { guidStr += Math.floor(Math.random() * 16).toString(16); } return this.formatGUID(guidStr); }; /* * 功能:获取当前日期的GUID格式,即8位数的日期:19700101 * 返回值:返回GUID日期格式的字条串 */ GUID.prototype.getGUIDDate = function () { return ( this.date.getFullYear() + this.addZero(this.date.getMonth() + 1) + this.addZero(this.date.getDay()) ); }; /* * 功能:获取当前时间的GUID格式,即8位数的时间,包括毫秒,毫秒为2位数:12300933 * 返回值:返回GUID日期格式的字条串 */ GUID.prototype.getGUIDTime = function () { return ( this.addZero(this.date.getHours()) + this.addZero(this.date.getMinutes()) + this.addZero(this.date.getSeconds()) + this.addZero(parseInt(this.date.getMilliseconds() / 10)) ); }; /* * 功能: 为一位数的正整数前面添加0,如果是可以转成非NaN数字的字符串也可以实现 * 参数: 参数表示准备再前面添加0的数字或可以转换成数字的字符串 * 返回值: 如果符合条件,返回添加0后的字条串类型,否则返回自身的字符串 */ GUID.prototype.addZero = function (num) { if (Number(num).toString() != 'NaN' && num >= 0 && num < 10) { return '0' + Math.floor(num); } else { return num.toString(); } }; /* * 功能:将y进制的数值,转换为x进制的数值 * 参数:第1个参数表示欲转换的数值;第2个参数表示欲转换的进制;第3个参数可选,表示当前的进制数,如不写则为10 * 返回值:返回转换后的字符串 */ GUID.prototype.hexadecimal = function (num, x, y) { if (y != undefined) { return parseInt(num.toString(), y).toString(x); } else { return parseInt(num.toString()).toString(x); } }; /* * 功能:格式化32位的字符串为GUID模式的字符串 * 参数:第1个参数表示32位的字符串 * 返回值:标准GUID格式的字符串 */ GUID.prototype.formatGUID = function (guidStr) { var str1 = guidStr.slice(0, 8) + '-', str2 = guidStr.slice(8, 12) + '-', str3 = guidStr.slice(12, 16) + '-', str4 = guidStr.slice(16, 20) + '-', str5 = guidStr.slice(20); return str1 + str2 + str3 + str4 + str5; }; } } export default new GUID();
index.js内容如下:
-
import { useState } from 'react'; import OSS from 'ali-oss'; import guid from './guid'; let credentials = { accessKeyId: '换成自己的accessKeyId', accessKeySecret: '换成自己的accessKeySecret', // stsToken: '', expiration: '2220-01-01T12:00:00.000Z', }; // STS凭证 const bucket = '填写bucket名称'; // bucket名称 const region = '填写oss服务区域名称'; // oss服务区域名称,比如oss-cn-beijing const partSize = 1 * 1024 * 1024; // 每个分片大小1MB const parallel = 3; // 同时上传的分片数 const ossClientMap = {}; // oss客户端实例 const checkpointMap = {}; // 所有分片上传文件的检查点 const optionMap = {}; const fileNameMap = {}; // 上边的一大坨东西需要自己去oss拿,建议问下后端 export default function useOss(newPath = '') { const [percent, setPercent] = useState(0); const [loading, setLoading] = useState(false); const [uuid] = useState(guid.newGUID()); // 获取STS Token function getCredential() { return getSecurityToken().then((res) => { credentials = { accessKeyId: res.accessKeyId, accessKeySecret: res.accessKeySecret, stsToken: res.token, expiration: res.expiration, }; return res; }); } // 创建OSS Client async function initOSSClient() { ossClientMap[uuid] = new OSS({ ...credentials, bucket, region, secure: true, }); } // 普通上传 async function commonUpload({ file, type, folderPath, ...options }) { if (!ossClientMap[uuid]) { await initOSSClient(); } return ossClientMap[uuid] .put(newPath + folderPath + options.fileName, file) .then((resFile) => { const { url } = resFile; // console.log(resFile, 'newPath'); return url; }) .catch((err) => { console.error(err); throw err; }); } const upload = async (initOptions) => { try { setLoading(true); checkpointMap[uuid] = {}; // 获取STS Token // await getCredential(); optionMap[uuid] = initOptions; return commonUpload({ ...optionMap[uuid] }); } catch (error) { if (error?.status !== 0) { initOptions.onError?.(error); throw error; } return null; } }; return { upload, }; }
index.tsx内容如下:
-
import React, { useState, useEffect, useRef } from 'react'; import { Input, Form, Button, Row, Col, Upload, Card } from 'antd'; import { DeleteOutlined } from '@ant-design/icons'; import useOss from './oss'; const ossUpload = (config) => { const { config: { name, btnName = '上传图片', label = '上传图片', callback, accept = 'image/*', maxCount = 1, multiple = false, ...reset }, } = config; const ipt = useRef(); const oss = useOss(''); //自定义上传 const uploadRequest = (opts) => { if (!opts) return; oss .upload({ file: opts, fileName: new Date().getTime() + `${opts.name}`, folderPath: `/test`, type: opts.type, onProgress: (e) => onProgress(e), onSuccess: (e) => onSuccess(e), }) .then((res) => { if (callback) { callback(res); } }); }; const onProgress = (e) => { console.log(e, 'p'); }; const onSuccess = (e) => { console.log(e, 's'); }; const normFile = (e: any) => { if (Array.isArray(e)) { return e; } return e && e.fileList; }; return ( <> <Form.Item name={name} label={label} labelCol={6} {...reset} valuePropName="fileList" getValueFromEvent={normFile} > <Upload listType="picture" customRequest={(e) => { uploadRequest(e.file); }} onRemove={(file) => { console.log(file); }} > <Button>{btnName}</Button> </Upload> </Form.Item> </> ); }; export default ossUpload;
阿里云web端上传组件封装 完毕!
-
使用:
-
import OssUpload from '@/components/ossUpload'; <OssUpload config={{ name: 'name1', label: '图片', callback: (e) => {}); }, maxCount: 1, }} ></OssUpload>
-
如果上传文件格式如下,则封装成功。