/
chooser.js
233 lines (187 loc) · 5.16 KB
/
chooser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import React, { Component, PropTypes } from 'react';
import SparkMD5 from 'spark-md5';
import BlueWhiteRaisedButton from '../../picker/button/raised/blue_white_raised_button';
import './chooser.scss';
/**
* @function 组件UploadChooser
*/
export default class UploadChooser extends Component {
static propTypes = {
// 判断是否允许选择多个文件
multiple: PropTypes.bool,
// 上传按钮显示的名称
label: PropTypes.string,
// 文件类型
types: PropTypes.arrayOf(PropTypes.string),
// 已存在的文件名
existedFiles: PropTypes.arrayOf(PropTypes.string),
// 判断是否需要进行MD5操作
md5: PropTypes.bool,
// 选择成功之后的回调事件
onChange: PropTypes.func,
// 显示的按钮
children: PropTypes.node
};
static defaultProps = {
multiple: false,
label: '本地上传',
// 设置为null表示可以上传任意文件
types: null,
// 设置为空数组表示没有现存的文件
existedFiles: [],
// 默认需要进行md5操作
md5: true,
onChange: (files: [object]) => {
files.forEach(file => {
console.log(file);
});
}
};
/**
* @function 默认构造函数
* @param props
*/
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
/**
* @function 组件挂载完成回调
*/
componentDidMount() {}
_onChange = () => {
const files = this.refs.upload.files;
// 如果没有选择文件则直接返回
if (files.length < 1) {
return;
}
const { existedFiles, md5, onChange } = this.props;
const willUploadFiles = [];
for (let index = 0; index < files.length; index++) {
if (existedFiles.indexOf(files[index].name) === -1) {
// 如果未发现重名
willUploadFiles.push(files[index]);
}
}
if (md5) {
// 对所有文件执行MD5计算操作
md5MultipleFiles(willUploadFiles, 0, [], md5s => {
for (let index = 0; index < willUploadFiles.length; index++) {
willUploadFiles[index].md5 = md5s[index];
}
onChange(willUploadFiles);
});
// 本函数执行返回
return;
}
// 如果选择了有效的文件,则触发外部函数
if (willUploadFiles.length) {
onChange(willUploadFiles);
}
// 重置当前表单
this.refs.form.reset();
};
/**
* @function 默认渲染函数
*/
render() {
const { label, multiple, types } = this.props;
let accept = '*';
// 根据设置的输入的可选文件类型判断是否限制文件类型
if (types) {
accept = types.join(',');
}
let children = this.props.children;
if (!this.props.children) {
children = (
<BlueWhiteRaisedButton
className="upload_chooser__button"
label={label}
reverse={false}
/>
);
}
return (
<div className="upload_chooser__container">
{children}
{/* 隐藏起来的文件上传表单 */}
<form ref="form">
{multiple
? <input
className="upload_chooser__input"
accept={accept}
onChange={this._onChange}
multiple
ref="upload"
type="file"
/>
: <input
className="upload_chooser__input"
accept={accept}
onChange={this._onChange}
ref="upload"
type="file"
/>}
</form>
</div>
);
}
}
/**
* @function 对多个文件执行MD5计算操作
* @param files
* @param index
* @param md5s
* @param cb
*/
function md5MultipleFiles(files: [object], index, md5s, cb) {
// 判断是否已经全部结束
if (index === files.length) {
// 全部结束则执行总回调
cb(md5s);
return;
}
// 否则对下一个元素执行MD5计算操作
md5SingleFile(files[index], md5 => {
// 将计算值添加到数组中
md5s.push(md5);
md5MultipleFiles(files, index + 1, md5s, cb);
});
}
/**
* @function 对文件执行MD5操作
* @param file
* @param cb
*/
function md5SingleFile(file: object, cb): string {
const blobSlice =
File.prototype.slice ||
File.prototype.mozSlice ||
File.prototype.webkitSlice;
const chunkSize = 2097152; // Read in chunks of 2MB
const chunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
function loadNext() {
const start = currentChunk * chunkSize;
const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
fileReader.onload = event => {
// 该值记录了对某个文件进行MD5操作的进度
const percent = parseFloat((currentChunk / chunks * 100).toFixed(1));
spark.append(event.target.result); // Append array buffer
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
const md5 = spark.end(); // 完成md5
cb(md5);
}
};
fileReader.onerror = () => {
console.warn('error.');
};
loadNext();
}