UNPKG

imgfunc

Version:

图片上传JS

210 lines (199 loc) 5.86 kB
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); };