建议先封装一下XhrRequest:
export default class xhrHelper {
static createXHR() {
if (typeof XMLHttpRequest !== "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject !== "undefined") {
let ActiveXObject = window.ActiveXObject;
let argumentsA = window.arguments;
if (typeof argumentsA.callee.activeXString !== "string") {
let versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"];
for (let i = 0, len = versions.length; i < len; i++) {
try {
let xhr = new ActiveXObject(versions[i]);
argumentsA.callee.activeXString = versions[i];
return xhr;
} catch (e) {
//跳过
}
}
}
return new ActiveXObject(argumentsA.callee.activeXString);
} else {
throw new Error("No XHR object available")
}
}
static sendXHRequest(formData, uri, onloadstartHandler, onprogressHandler, onloadHandler, onreadystatechangeHandler) {
// Get an XMLHttpRequest instance
let xhr = this.createXHR();
// Set up events
xhr.upload.addEventListener('loadstart', onloadstartHandler, false);
xhr.upload.addEventListener('progress', onprogressHandler, false);
xhr.upload.addEventListener('load', onloadHandler, false);
xhr.addEventListener('readystatechange', onreadystatechangeHandler, false);
// Set up request
xhr.open('POST', uri, true);
// Fire!
xhr.send(formData);
return xhr;
}
}
在调用xhr的时候,可以获取xhr对象(代码不可复制直接用,仅供参考)。
实例代码如下,主要是查看Xhr的几个事件,详情查看:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest/upload
import React from 'react';
import VideoPlayer from '../../common/commonComponent/player';
import MessageModal from '../../common/commonComponent/modalMessage';
import ErrorHandler from "../../common/error-handler";
import ServiceProxy from '../../service-proxy';
import xhrHelper from '../../common/xhrRequestHelper';
import './my-video.css';
export default class VideoLabel extends React.Component {
constructor() {
super();
this.state = {
lastSrc: '',
progress: 'Uploading...'
};
this.handleVideoChange = this.handleVideoChange.bind(this);
this.handleVideoChangeNone = this.handleVideoChangeNone.bind(this);
this.onloadstartHandler = this.onloadstartHandler.bind(this);
this.onloadHandler = this.onloadHandler.bind(this);
this.onprogressHandler = this.onprogressHandler.bind(this);
this.onreadystatechangeHandler = this.onreadystatechangeHandler.bind(this);
this.onabortHandler = this.onabortHandler.bind(this);
this.uploadErrHandler = this.uploadErrHandler.bind(this);
this.abortUpload = this.abortUpload.bind(this);
}
handleVideoChangeNone(){
this.props.onChange({
target: {
name: this.props.name,
value: ''
}
});
}
render() {
return <div className="video-label">
<MessageModal modalName={this.state.messageName}
modalContent={this.state.messageContent}
modalShow={this.state.messageModal}/>
{
this.state.loadingModal && <div className="uploading">
<div className="content-load">
<img src="//cdn-corner.resource.buzzbuzzenglish.com/icon_user_video.svg" alt=""/>
<div>{this.state.progress}</div>
<div className="cancel" onClick={this.abortUpload}>Cancel</div>
</div>
</div>
}
<div className="label">
{this.props.label || 'Video about myself'}
{
this.props.value ?
<div className="upload">
<img src="//cdn-corner.resource.buzzbuzzenglish.com/upload/icon_Upload.svg" alt=""/>Reupload
<input type="file" className="upload-input-file" accept="video/*" ref="uploadAgain"
onChange={(e) => this.handleVideoChange(e)}
/>
</div> : ''
}
</div>
<div className="video-with-label" style={this.props.style ? this.props.style : {}}>
{
this.props.value ?
<VideoPlayer videoSrc={this.props.value}
/> :
<div className="upload-video" style={{height: document.documentElement.clientWidth * 9 / 16 > 450 ? 450 : document.documentElement.clientWidth * 9 / 16}}>
<img src="//cdn-corner.resource.buzzbuzzenglish.com/upload/icon_Upload.svg" alt=""/>
<div className="info">
<p className="title">Click to upload</p>
<p>Name/Age/Grade/Country/Hobbies/why do you want to be a BuzzKid Language, Pal/use landscape mode.</p>
</div>
<input type="file" className="upload-input-file" accept="video/*" ref="uploadFirst"
onChange={(e) => this.handleVideoChange(e)}
/>
</div>
}
</div>
</div>
}
async handleVideoChange(e) {
let video = e.target;
try {
if (video.files[0].type && video.files[0].type.indexOf('video') < 0 && video.files[0].size && video.files[0].size < 200 * 1024 * 1024) {
//error
this.setState({
messageModal: true,
messageName: 'error',
messageContent: video.files[0].type.indexOf('video') === 0 ? 'Wrong type file' : 'The file too large to upload'
});
this.closeMessageModal();
return;
}
this.setState({loadingModal: true});
let qiniu_token = await ServiceProxy.proxyTo({
body: {
uri: '{config.endPoints.buzzService}/api/v1/qiniu/token',
method: 'GET'
}
});
if (!qiniu_token.uptoken) {
throw new Error('Wrong qiniu token');
}
let fileForm = new FormData();
fileForm.append("name", video.files[0].name);
fileForm.append("file", video.files[0]);
fileForm.append("token", qiniu_token.uptoken);
this.setState({
resources_url: qiniu_token.resources_url,
xhr: xhrHelper.sendXHRequest(fileForm, qiniu_token.upload_url, this.onloadstartHandler, this.onprogressHandler, this.onloadHandler, this.onreadystatechangeHandler)
});
} catch (ex) {
//something wrong
ErrorHandler.notify('Uploading failed', ex);
this.setState({
loadingModal: false,
messageModal: true,
messageContent: 'Upload failed, try later.'
});
this.closeMessageModal();
}
};
closeMessageModal() {
const interval = setTimeout(() => {
if (this.state.messageModal) {
this.setState({messageModal: false});
}
clearTimeout(interval);
//browserHistory.push('/user?refresh=true');
}, 2000)
}
onloadstartHandler(evt) {
this.setState({
progress: 'Uploading...'
});
}
onloadHandler(evt) {
}
abortUpload(){
if(this.state.xhr){
this.state.xhr.abort();
this.onabortHandler();
}
}
async onabortHandler(){
if(this.props.value){
this.refs.uploadAgain.value = '';
this.setState({
progress: 'Canceled!'
});
}else{
this.refs.uploadFirst.value = '';
this.setState({
progress: 'Canceled!'
});
}
await new Promise(resolve => window.setTimeout(resolve, 2000));
this.uploadErrHandler('Uploading cancelled!');
}
onprogressHandler(evt) {
this.setState({
progress: Math.floor(evt.loaded/evt.total*100) + '%'
});
}
async onreadystatechangeHandler(evt) {
let status = '', text = '', readyState = '';
try {
text = evt.target.responseText;
status = evt.target.status;
readyState = evt.target.readyState;
}
catch(e) {
return;
}
if (readyState === 4 && status === 200 && text) {
try {
let result = JSON.parse(text);
if (!result.key || !result.hash) {
this.uploadErrHandler();
} else {
if(this.props.onChange){
this.props.onChange({
target: {
name: this.props.name,
value: this.state.resources_url + result.key
}
});
}
await new Promise(resolve => window.setTimeout(resolve, 2000));
this.setState({
loadingModal: false
});
}
}
catch (ex){
this.uploadErrHandler();
}
}
}
uploadErrHandler(meg){
this.setState({
loadingModal: false,
messageModal: true,
messageContent: meg || 'Upload failed, try later.'
});
this.closeMessageModal();
}
}