imgfunc
Version:
图片上传JS
210 lines (199 loc) • 5.86 kB
JavaScript
import { UPLOADERROR } from "./errorType";
import {STATIC_TIMEOUT, STATIC_RESPONSE_ERROR, STATIC_EXCHANGE_ERROR} from './statusEnum'
// TODO: 上传后续考虑 业务传入的 axios
class XHRUpload {
constructor({
changeType = "image/jpeg",
base64 = null,
beforeUpload,
uploading,
successUpload,
errorUpload,
xhrParam,
uploadUrl,
uploadTimeout,
formdataName = "file",
fileName='blob'
}) {
this.base64 = base64;
this.beforeUpload = beforeUpload;
this.uploading = uploading;
this.successUpload = successUpload;
this.errorUpload = errorUpload;
this.changeType = changeType;
this.uploadUrl = uploadUrl;
this.uploadTimeout = uploadTimeout;
// 上传的额外参数
this.xhrParam = xhrParam;
this.formdataName = formdataName;
this.fileName = fileName;
this.xhrUpload(base64);
}
xhrUpload(dataBase64) {
const xhr = new XMLHttpRequest();
const formdata = this.getFormData();
const blob = this.dataURLtoBlob(dataBase64);
const filename = this.fileName;
formdata.append(this.formdataName, blob, filename);
// 这里是重写XHR 所以这个xhrParam必须是对象
const xhrParam = this.xhrParam;
if (xhrParam && xhrParam instanceof Object) {
Object.keys(this.xhrParam).map(keys => {
formdata.append(keys, this.xhrParam[keys]);
});
}
if (xhrParam && !xhrParam instanceof Object) {
console.error("xhrParam必须是对象");
return;
}
const parDate = new Date() * 1;
xhr.open("post", `${this.uploadUrl}?_=${parDate}`);
let timeout = this.uploadTimeout;
const uploadTimer = setTimeout(function() {
timeout = 0;
xhr.abort(); // 请求中止
}, timeout * 1000);
xhr.onreadystatechange = () => {
if (timeout <= 0) {
this.errorUpload({
message: "上传超时",
errorType: UPLOADERROR,
status: STATIC_TIMEOUT
});
xhr.abort(); // 请求中止
}
if (Number(xhr.readyState) === 4) {
clearTimeout(uploadTimer);
try {
const responseData = JSON.parse(xhr.responseText);
this.successUpload && this.successUpload(responseData);
} catch (err) {
this.errorUpload({
message: "上传失败",
errorType: UPLOADERROR,
status: STATIC_RESPONSE_ERROR
});
}
}
};
xhr.send(formdata);
}
/**
* 把图片转成formdata 可以使用的数据...
*这里要把\s替换掉..要不然atob的时候会出错....
*/
dataURLtoBlob(data) {
const tmp = data.split(",");
tmp[1] = tmp[1].replace(/\s/g, "");
const binary = atob(tmp[1]);
const array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return this.getBlob(new Uint8Array(array), this.changeType);
}
/**
* 获取blob对象的兼容性写法
* @param buffer
* @param format
* @returns {*}
*/
getBlob(data, datatype) {
const _that = this;
let result;
try {
if (datatype) {
result = new Blob([data], { type: datatype });
} else {
result = new Blob(data);
}
// 一切正常,直接使用blob.
} catch (e) {
const BlobBuilder =
window.BlobBuilder ||
window.WebKitBlobBuilder ||
window.MozBlobBuilder ||
window.MSBlobBuilder;
// 使用blobbuilder来生成文件..
if (e.name === "TypeError" && BlobBuilder) {
const bob = new BlobBuilder();
bob.append(data.buffer);
result = bob.getBlob(datatype);
} else {
_that.errorUpload({
message: "blob转换错误",
errorType: BLOBCHANGEERROR,
status: STATIC_EXCHANGE_ERROR
});
}
}
return result;
}
/**
* 获取formdata
*/
getFormData() {
if (window.FormData) {
return new window.FormData();
} else {
return this.formDataShim();
}
}
/**
* formdata 补丁, 给不支持formdata上传blob的android机打补丁
* @constructor
*/
formDataShim() {
const that = this;
const parts = []; // Data to be sent
const boundary =
Array(5).join("-") + (+new Date() * (1e16 * Math.random())).toString(32);
const oldSend = XMLHttpRequest.prototype.send;
// 把xhr的send方法重写一下.
XMLHttpRequest.prototype.send = function(xhrs) {
// XMLHttpRequest调用send,传递 formDataShim返回值
if (xhrs.isSelfFormdata === true) {
const data = that.getBlob(that.parts);
const fr = new FileReader();
fr.onload = () => {
oldSend.call(this, fr.result);
};
fr.onerror = function(err) {
throw err;
};
fr.readAsArrayBuffer(data);
// 设置content-type
this.setRequestHeader(
"Content-Type",
`multipart/form-data; boundary=${boundary}`
);
XMLHttpRequest.prototype.send = oldSend;
} else {
oldSend.call(this, xhrs);
}
};
return {
append: (name, value, filename) => {
parts.push(
`\r\n--${boundary}\r\nContent-Disposition: form-data; name="${name}"`
);
if (value instanceof Blob) {
parts.push(
`; filename="blob"\r\nContent-Type: ${value.type}\r\n\r\n`
);
parts.push(value);
} else {
parts.push(`\r\n\r\n${value}`);
}
parts.push("\r\n");
// 最后加一下boundary..注意这里一定要在最后加\r\n..否则服务器有可能会解析参数失败..
parts.push(`\r\n--${boundary}--\r\n`);
this.parts = parts;
},
isSelfFormdata: true
};
}
}
export default (...args) => {
return new XHRUpload(...args);
};