mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-03 04:30:06 +08:00
Merge pull request #459 from ant-design/feat-upload
feat add upload progress effect
This commit is contained in:
commit
5616e552a4
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -32,4 +32,3 @@ ReactDOM.render(
|
||||
</Upload>
|
||||
, document.getElementById('components-upload-demo-multiple'));
|
||||
````
|
||||
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
文件状态改变的回调,返回为:
|
||||
|
@ -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>
|
||||
);
|
||||
});
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user