import { noop } from "../_util/noop"; export interface ProgressInfo { /** * 文件总大小 */ total: number; /** * 已上传部分大小 */ loaded: number; /** * 百分比 */ percent: number; } export interface UploadEventContext { /** * 进度事件 */ event: ProgressEvent; /** * XHR 对象 */ xhr: XMLHttpRequest; /** * 当前文件 */ file: File; } export interface UploadOption { action: string; file: File; filename: string; data?: object; headers?: object; withCredentials?: boolean; method?: string; send?: (file: File, formData: FormData) => BodyInit; onProgress?: (progress: ProgressInfo, context: UploadEventContext) => void; onSuccess?: (result: object | string, context: UploadEventContext) => void; onError?: (error: Error, context: UploadEventContext) => void; } export function upload({ action, file, filename, data = {}, headers = {}, method = "POST", withCredentials = false, send = (_, data) => data, onProgress = noop, onSuccess = noop, onError = noop, }: UploadOption) { const formData = new FormData(); const xhr = new XMLHttpRequest(); xhr.onload = event => { if (!(xhr.status >= 200 && xhr.status < 300)) { const error = new Error(`${xhr.status} ${xhr.statusText}`); onError(error, { event, xhr, file }); return; } const text = xhr.responseText || xhr.response; let result; try { result = JSON.parse(text); } catch (err) { result = text; } onSuccess(result, { event, xhr, file }); }; xhr.onerror = event => onError(new Error("Http Request Error"), { event, xhr, file }); if (onProgress && xhr.upload) { xhr.upload.onprogress = event => { if (event.lengthComputable && event.total) { onProgress( { total: event.total, loaded: event.loaded, percent: (event.loaded / event.total) * 100, }, { event, xhr, file } ); } }; } Object.keys(data).forEach(key => { formData.append(key, data[key]); }); formData.append(filename, file); xhr.open(method, action, true); xhr.withCredentials = withCredentials; Object.keys(headers).forEach(key => { xhr.setRequestHeader(key, headers[key]); }); xhr.send(send(file, formData)); return xhr; }