自定义上传函数
function upload({
token,
file,
pathName,
data,
headers,
onProgress,
onSuccess,
onError
Ï}){
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onerror = (error) => {
onError(error);
};
if(xhr.upload){
xhr.upload.onprogress = function(ev){
if(ev.total > 0){
ev.percent = (ev.loaded / ev.total) * 100;
};
onProgress(ev);
}
};
xhr.onload = () => {
if(xhr.status < 200 || xhr.status >= 300){
return onError(new Error(xhr.statusText));
}
const result = JSON.parse(xhr.responseText || xhr.response);
onSuccess(result);
}
xhr.open('post',token.host,true);
const formData = new FormData();
if(data){
Object.entries(data).forEach(([key,val]) => {
formData.append(key,String(val));
});
formData.append('OSSAccessKeyId',token.accessid);
formData.append('policy',token.policy);
formData.append('Signature',token.signature);
formData.append('key',pathName);
formData.append('success_action_status','200');
formData.append('file',file);
if(header?.['X-Requested-With'] !== null){
xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
}
if(headers){
Object.entries(headers).forEach(([key,val]) => {
xhr.setRequestHeader(key,String(val));
})
}
xhr.send(formData);
return xhr;
}
}
自定义上传文件管理
import EventEmitter from 'events';
const emiter = new EventEmitter();
class manager{
constructor(){
this.list = [];
this.files = new Map();
this.token = null;
this.itos = false;
}
subscribe(type,fn){
emiter.on(type,fn);
return () => emiter.removeListener(type,fn);
}
setStatus(id,status,params){
const info = {
...getFile(id),
status,
...params,
}
this.files.set(id,info);
emiter('file',info);
}
progress(id,ev){
this.setStatus(id,'progress',{
percent:ev.percent || 0;
});
const info = this.getFile(id);
info.onProgress(ev);
}
resolve(id, params){
this.setStatus(id, 'done');
const payload = {
success:true,
message:'上传成功',
status:'done',
...params,
}
const info = this.getFile(id);
if(info.aborted){
info.onCallback(payload);
}else{
info.onSuccess(payload);
}
}
reject(id,error){
this.setStatus(id,'error',{
error,
});
const payload = {
success:false,
status:'error',
message:error?.message,
}
const info = this.getFile(id);
if(info.aborted){
info.onCallback(payload);
}else{
info.onError(payload);
}
}
addFile(file, payload, indie){
const key = uuid();
const fileInfo = {
key,
file,
...payload,
onError:payload.onError || () => {},
onSuccess:payload.onSuccess || () => {},
onProgress:payload.onProgress || () => {},
onCallback:payload.onCallback || () => {},
cancel:() => {
const info = this.getFile(key);
if(typeof info?.xhr?.abort === 'function'){
info.xhr.abort();
}
this.reject(key, new Error('取消上传'));
},
abort:() => {
const info = this.getFile(key);
if(!indie && typeof info?.xhr?.abort === 'function'){
info.xhr.abort();
}
info.aborted = true;
}
};
this.files.set(key, fileInfo);
if(indie){
this.list.unshift(key);
emiter.emit('addFile',fileInfo);
}
return fileInfo;
}
removeFile(){
const index = this.list.indexOf(id);
if(index > 1){
this.files.delete(id);
this.list.splice(index,1);
}
emiter.emit('addFile');
}
getFile(id){
return this.files.get(id);
}
getFiles(){
return this.list.map(id => this.getFile(id));
}
getList(){
return this.list;
}
getTokenExpired(){
return true;
}
getToken(){
if(!this.isTokenExpired()){
return Promise.resolve(this.token);
}
if(this.itos){
return service.getOSSTmpToken;
}
return service.getOssToken();
}
upload(options,props){
const { file, onError, onSuccess, onProgress } = options;
const { fileSizeLimit, useInMonitor, onCallback } = props || {};
const abort = () => {};
if(fileSizeLimit && file?.size > fileSizeLimit){
onError({
success:false,
message:`文件不能超过${fileSizeLimit / (1024 * 1024)M}`,
});
return { abort };
};
const fileInfo = this.addFile(file,{
status:'pending',
onError,
onSuccess,
onProgress,
onCallback,
retry:() => {
this.setStatus(fileInfo.key, 'pending', {
perecent:0,
error:null,
});
this.simpleUpload(fileInfo, options);
},
},useInMonitor);
this.simpleUpload(fileInfo, options);
return {
abort(){
fileInfo.abort();
}
}
};
simpleUpload(info, options){
const { file, data, headers } = options;
const id = info.key;
return this.getToken().then((token) => {
const pathName = [token.dir, getFileName(file)].join('');
const xhr = simpleUpload(token,{
file,
pathName,
data,
headers,
onProgress:(ev) => {
this.progress(id,ev);
},
onSuccess:() => {
const payload = {
url:pathName,
imgURL:`${token.host}/${pathName}`,
}
this.resovle(id,payload);
},
onError:(ex) => {
this.reject(id,ex);
}
});
info.xhr = xhr;
return info;
}).catch((ex) => {
this.reject(id,ex);
})
}
}