lm-upload
Version:
* 作者:quying * 邮箱:qy9404@163.com * 版本:**`0.2.0`**
255 lines (211 loc) • 7.09 kB
JavaScript
/**
* Created by quying<qy9404@163.com>.
* ComponentName Upload
* Desc 组件描述内容
* GroupName lm-component
*/
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import './index.scss'
import getUid, { initFileList } from './uid';
import defaultUpload from './request';
/**
* @class Upload
* @extends React.Component
* @desc Upload Component for mobile
*/
export default class Upload extends Component {
static propTypes = {
name: PropTypes.string, //文件名
accept: PropTypes.string, //接受的文件类型
multiple: PropTypes.bool, //是否支持多选文件
onInputChange: PropTypes.func, //(files) = > boolean | Promise
beforeUpload: PropTypes.func, //(file, fileList) => boolean | Promise
customUpload: PropTypes.func, //通过覆盖默认的上传行为,可以自定义自己的上传实现
disabled: PropTypes.bool, //是否禁用
action: PropTypes.string, //上传的地址
data: PropTypes.oneOfType([ //表单数据
PropTypes.object,
PropTypes.func
]),
headers: PropTypes.object, //xhr请求头
onStart: PropTypes.func, //开始上传回调
onProgress: PropTypes.func, //上传进度 onProgress(e, file)
onSuccess: PropTypes.func, //上传成功回调 onSuccess(ret, file, xhr)
withCredentials: PropTypes.bool, //允许跨域发送cookie
appUpload: PropTypes.func, //调用app上传
};
static defaultProps = {
multiple: false,
disabled: false,
isApp: false,
onStart: ()=>{},
beforeUpload: ()=>{},
onError: ()=>{}
};
reqs = {}
/**
* @constructor
*/
constructor(props) {
super(props);
this.state = {
uid: getUid()
}
this.changeHandler = this.changeHandler.bind(this);
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
this.abort();
}
onClick = () => {
const { appUpload } = this.props;
if(appUpload) {
return appUpload();
}
const el = this.fileInput;
if(!el) {
return;
}
el.click();
}
changeHandler(e){
const files = e.target.files;
const { onInputChange } = this.props;
if(onInputChange) {
const changedRet = onInputChange(files);
if (changedRet && changedRet.then) {
changedRet.then((processedFiles) => {
this.uploadFiles(processedFiles);
}).catch(e => {
console && console.log(e);
});
} else if (changedRet !== false) {
this.uploadFiles(changedRet);
}
} else {
this.uploadFiles(files);
this.reset();
}
e.target.value = '';
}
uploadFiles(files) {
let fileList = Array.prototype.slice.call(files);
fileList.forEach((file) => {
file.uid = getUid();
this.upload(file, fileList);
});
}
upload(file, fileList) {
const { props } = this;
if(!props.beforeUpload) {
this.post(file);
}
//返回 false 则停止上传。支持返回一个 Promise 对象,Promise 对象 reject 时则停止上传,resolve 时开始上传
const before = props.beforeUpload(file, fileList);
if (before && before.then) {
before.then((processedFile) => {
const processedFileType = Object.prototype.toString.call(processedFile);
if(processedFileType === '[object String]' || processedFileType === '[object Blob]') {
this.post(file, processedFile);
} else {
this.post(file);
}
}).catch(e => {
console && console.log(e);
});
} else if (before !== false) {
this.post(file);
}
}
post(file, processedFile) {
if (!this._isMounted) {
return;
}
let { data } = this.props;
if (typeof data === 'function') {
let dataRet = data(file);
if(dataRet.then) {
dataRet.then(ret => {
data = ret;
this.send(data, file, processedFile);
})
} else {
data = dataRet;
this.send(data, file, processedFile)
}
}
}
send(data, file, processedFile) {
const { props } = this;
const { uid } = file;
const { onStart, onProgress } = props;
const request = props.customUpload || defaultUpload;
this.reqs[uid] = request({
action: props.action,
filename: props.name,
file: processedFile || file,
data,
headers: props.headers,
withCredentials: props.withCredentials,
onProgress: onProgress ? e => {
onProgress(e, file);
} : null,
onSuccess: (ret, xhr) => {
delete this.reqs[uid];
props.onSuccess(ret, file, xhr);
},
onError: (err, ret) => {
delete this.reqs[uid];
props.onError(err, ret, file);
},
});
onStart(file);
}
reset() {
this.setState({
uid: getUid()
})
}
abort(file) {
const { reqs } = this;
if(file) {
let uid = file;
if(file.uid) {
uid = file.uid;
}
if(reqs[uid]) {
reqs[uid].abort();
delete reqs[uid];
}
} else {
Object.keys(reqs).forEach((uid) => {
if(reqs[uid]) {
reqs[uid].abort();
}
delete reqs[uid];
})
}
}
render () {
let { className, accept, multiple, disabled, children, style } = this.props;
return (
<span className={ className } onClick={ this.onClick } style={style}>
<input
type="file"
ref={ (node) => this.fileInput = node }
style={{ display: 'none'}}
accept={ accept }
multiple={ multiple }
disabled={ disabled }
onChange={ this.changeHandler } />
{ children }
</span>
)
}
}
Upload.initFileList = initFileList;