Merge pull request #459 from ant-design/feat-upload

feat add upload progress effect
This commit is contained in:
偏右 2015-11-04 11:19:03 +08:00
commit 5616e552a4
7 changed files with 140 additions and 54 deletions

View File

@ -12,6 +12,7 @@ const Dragger = Upload.Dragger;
const props = {
name: 'file',
showUploadList: false,
action: '/upload.do'
};
@ -26,6 +27,5 @@ ReactDOM.render(
<style>
#components-upload-demo-drag-simple {
width: 246px;
height: 146px;
}
</style>

View File

@ -12,6 +12,7 @@ const Dragger = Upload.Dragger;
const props = {
name: 'file',
showUploadList: false,
action: '/upload.do'
};
@ -26,9 +27,3 @@ ReactDOM.render(
document.getElementById('components-upload-demo-drag')
);
````
<style>
#components-upload-demo-drag {
height: 300px;
}
</style>

View File

@ -32,4 +32,3 @@ ReactDOM.render(
</Upload>
, document.getElementById('components-upload-demo-multiple'));
````

View File

@ -19,7 +19,30 @@ function fileToObject(file) {
type: file.type,
uid: file.uid,
response: file.response,
error: file.error
error: file.error,
percent: 0
};
}
/**
* 生成Progress percent: 0.1 -> 0.98
* - for ie
*/
function genPercentAdd() {
let k = 0.1;
const i = 0.01;
const end = 0.98;
return function(start) {
if (start >= end) {
return start;
} else {
start += k;
k = k - i;
if (k < 0.001) {
k = 0.001;
}
}
return start * 100;
};
}
@ -48,6 +71,20 @@ const AntUpload = React.createClass({
file: targetItem,
fileList: nextFileList
});
// fix ie progress
if (!window.FormData) {
this.autoUpdateProgress(0, targetItem);
}
},
autoUpdateProgress(percent, file) {
const getPercent = genPercentAdd();
let curPercent = 0;
this.progressTimer = setInterval(() => {
curPercent = getPercent(curPercent);
this.onProgress({
percent: curPercent
}, file);
}, 200);
},
removeFile(file) {
let fileList = this.state.fileList;
@ -60,6 +97,7 @@ const AntUpload = React.createClass({
return null;
},
onSuccess(response, file) {
this.clearProgressTimer();
// json
//
try {
@ -85,15 +123,16 @@ const AntUpload = React.createClass({
onProgress(e, file) {
let fileList = this.state.fileList;
let targetItem = getFileItem(file, fileList);
if (targetItem) {
this.onChange({
event: e,
file: file,
fileList: this.state.fileList
});
}
if (!targetItem) return;
targetItem.percent = e.percent;
this.onChange({
event: e,
file: file,
fileList: this.state.fileList
});
},
onError(error, response, file) {
this.clearProgressTimer();
let fileList = this.state.fileList;
let targetItem = getFileItem(file, fileList);
targetItem.error = error;
@ -115,13 +154,9 @@ const AntUpload = React.createClass({
this.handleRemove(file);
},
onChange(info) {
// 1. fileList
// 2. info.event fileList
if (!('fileList' in this.props) && !info.event) {
this.setState({
fileList: info.fileList
});
}
this.setState({
fileList: info.fileList
});
this.props.onChange(info);
},
getDefaultProps() {
@ -133,6 +168,7 @@ const AntUpload = React.createClass({
data: {},
accept: '',
onChange: noop,
showUploadList: true
};
},
componentWillReceiveProps(nextProps) {
@ -142,6 +178,9 @@ const AntUpload = React.createClass({
});
}
},
clearProgressTimer() {
clearInterval(this.progressTimer);
},
render() {
let type = this.props.type || 'select';
let props = assign({}, this.props, {
@ -150,14 +189,29 @@ const AntUpload = React.createClass({
onProgress: this.onProgress,
onSuccess: this.onSuccess,
});
let uploadList;
if (this.props.showUploadList) {
uploadList = <UploadList items={this.state.fileList} onRemove={this.handleManualRemove} />;
}
if (type === 'drag') {
let dragUploadingClass = '';
let fileList = this.state.fileList;
for (let i = 0; i < fileList.length; i ++) {
if (fileList[i].status === 'uploading') {
dragUploadingClass = ` ${prefixCls}-drag-uploading`;
break;
}
}
return (
<div className={prefixCls + ' ' + prefixCls + '-drag'}>
<Upload {...props}>
<div className={prefixCls + '-drag-container'}>
{this.props.children}
</div>
</Upload>
<div className={prefixCls + ' ' + prefixCls + '-drag-area'}>
<div className={prefixCls + ' ' + prefixCls + '-drag' + dragUploadingClass}>
<Upload {...props}>
<div className={prefixCls + '-drag-container'}>
{this.props.children}
</div>
</Upload>
</div>
{ uploadList }
</div>
);
} else if (type === 'select') {
@ -168,8 +222,7 @@ const AntUpload = React.createClass({
{this.props.children}
</Upload>
</div>
<UploadList items={this.state.fileList}
onRemove={this.handleManualRemove} />
{ uploadList }
</div>
);
}

View File

@ -23,10 +23,12 @@
| name | 可选参数, 上传的文件 | String | file |
| action | 必选参数, 上传的地址 | String | 无 |
| data | 可选参数, 上传所需参数 | Object | 无 |
|showUploadList | 可选参数, 是否展示 uploadList, 默认开启 | Boolean | true |
| multiple | 可选参数, 是否支持多选文件,支持 `ie10+` | Boolean | false |
| accept | 可选参数, 接受上传的文件类型, 详见 input accept Attribute | String | 无 |
| onChange | 可选参数, 上传文件改变时的状态,详见 onChange | Function | 无 |
### onChange
文件状态改变的回调,返回为:

View File

@ -1,33 +1,41 @@
import React from 'react';
import Animate from 'rc-animate';
import Icon from '../iconfont';
const prefixCls = 'ant-upload';
import {Line} from '../progress';
export default React.createClass({
getDefaultProps() {
return {
items: []
items: [],
progressAttr: {
strokeWidth: 3,
showInfo: false
}
};
},
handleClose(file) {
this.props.onRemove(file);
},
render() {
let list = this.props.items.map((file) => {
let statusIcon = file.status === 'done' ?
<Icon type="check" className={prefixCls + '-success-icon'} /> :
<Icon type="loading" />;
let filename = file.url ?
<a className={prefixCls + '-item-name'} href={file.url} target="_blank">{file.name}</a> :
<b className={prefixCls + '-item-name'}>{file.name}</b>;
let progress;
let infoUploadingClass = '';
if (file.status === 'uploading') {
progress = <div className={prefixCls + '-list-item-progress'}>
<Line {...this.props.progressAttr} percent={file.percent} />
</div>;
infoUploadingClass = ' ' + prefixCls + '-list-item-uploading';
}
return (
<div className={prefixCls + '-list-item'} key={file.uid}>
{statusIcon}
{filename}
<Icon type="cross" ref="thisCloseBtn" onClick={this.handleClose.bind(this, file)} />
<div className={prefixCls + '-list-item' + infoUploadingClass} key={file.uid}>
<div className={prefixCls + '-list-item-info'}>
<Icon type="paper-clip" />
<span className="ant-upload-item-name">{file.name}</span>
<Icon type="cross" ref="theCloseBtn"
onClick={this.handleClose.bind(this, file)} />
</div>
{ progress }
</div>
);
});

View File

@ -5,7 +5,6 @@
> span {
display: block;
width: 100%;
height: 100%;
}
input[type=file] {
@ -23,11 +22,12 @@
border-radius: @border-radius-base;
text-align: center;
width: 100%;
height: 100%;
height: 180px;
position: relative;
> span {
display: table;
height: 100%;
}
.@{upload-prefix-cls}-drag-container {
@ -38,6 +38,11 @@
&:hover {
border: 1px dashed #999;
}
&.@{upload-prefix-cls}-drag-uploading {
border-color: tint(@primary-color, 20%);
}
p.@{upload-prefix-cls}-drag-icon {
.anticon {
font-size: 80px;
@ -70,23 +75,47 @@
.@{upload-prefix-cls}-list {
margin-left: 4px;
margin-top: 8px;
overflow: hidden;
.@{upload-prefix-cls}-list-item {
margin-bottom: 4px;
height: 22px;
overflow: hidden;
.anticon {
margin-top: -2px;
font-size: 12px;
&.anticon-cross {
margin-top: 8px;
color: #999;
:hover {
background-color: tint(@primary-color, 90%);
.anticon.anticon-cross {
display: inline-block;
}
}
&.@{upload-prefix-cls}-list-item-uploading {
color: #BCBCBC;
}
.@{upload-prefix-cls}-list-item-info {
.anticon-paper-clip {
margin-left: 4px;
font-size: 12px;
}
.anticon-cross {
display: none;
cursor: pointer;
float: right;
margin-right: 8px;
color: #999;
&:hover {
color: #666;
}
}
}
.@{upload-prefix-cls}-list-item-progress {
padding: 0 8px 0 20px;
margin-top: -2px;
margin-bottom: 1px;
font-size: 12px;
.ant-progress-line-inner {
vertical-align: middle;
}
}
}
.@{upload-prefix-cls}-item-name {
font-size: 12px;