diff --git a/components/upload/demo/drag-simple.md b/components/upload/demo/drag-simple.md index 5f4e36adc3..27003ab633 100644 --- a/components/upload/demo/drag-simple.md +++ b/components/upload/demo/drag-simple.md @@ -12,6 +12,7 @@ const Dragger = Upload.Dragger; const props = { name: 'file', + showUploadList: false, action: '/upload.do' }; @@ -26,6 +27,5 @@ ReactDOM.render( diff --git a/components/upload/demo/drag.md b/components/upload/demo/drag.md index 34eb582151..4862b7039b 100644 --- a/components/upload/demo/drag.md +++ b/components/upload/demo/drag.md @@ -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') ); ```` - - diff --git a/components/upload/demo/multiple.md b/components/upload/demo/multiple.md index 600afbef48..a76ec7696b 100644 --- a/components/upload/demo/multiple.md +++ b/components/upload/demo/multiple.md @@ -32,4 +32,3 @@ ReactDOM.render( , document.getElementById('components-upload-demo-multiple')); ```` - diff --git a/components/upload/index.jsx b/components/upload/index.jsx index 52edc5e121..f2fdc878fb 100644 --- a/components/upload/index.jsx +++ b/components/upload/index.jsx @@ -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 = ; + } 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 ( -
- -
- {this.props.children} -
-
+
+
+ +
+ {this.props.children} +
+
+
+ { uploadList }
); } else if (type === 'select') { @@ -168,8 +222,7 @@ const AntUpload = React.createClass({ {this.props.children}
- + { uploadList } ); } diff --git a/components/upload/index.md b/components/upload/index.md index 9483b3607b..4583634cbc 100644 --- a/components/upload/index.md +++ b/components/upload/index.md @@ -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 文件状态改变的回调,返回为: diff --git a/components/upload/uploadList.jsx b/components/upload/uploadList.jsx index cec526233a..ae9e6dffc1 100644 --- a/components/upload/uploadList.jsx +++ b/components/upload/uploadList.jsx @@ -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' ? - : - ; - let filename = file.url ? - {file.name} : - {file.name}; + let progress; + let infoUploadingClass = ''; + if (file.status === 'uploading') { + progress =
+ +
; + infoUploadingClass = ' ' + prefixCls + '-list-item-uploading'; + } return ( -
- {statusIcon} - {filename} - +
+
+ + {file.name} + +
+ { progress }
); }); diff --git a/style/components/upload.less b/style/components/upload.less index e906a9c410..3ff397c7d3 100644 --- a/style/components/upload.less +++ b/style/components/upload.less @@ -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;