<script> import UploadList from './upload-list'; import Upload from './upload'; import ElProgress from 'element-ui/packages/progress'; import Migrating from 'element-ui/src/mixins/migrating'; function noop() {} export default { name: 'ElUpload', mixins: [Migrating], components: { ElProgress, UploadList, Upload }, provide() { return { uploader: this }; }, inject: { elForm: { default: '' } }, props: { action: { type: String, required: true }, headers: { type: Object, default() { return {}; } }, data: Object, multiple: Boolean, name: { type: String, default: 'file' }, drag: Boolean, dragger: Boolean, withCredentials: Boolean, showFileList: { type: Boolean, default: true }, accept: String, type: { type: String, default: 'select' }, beforeUpload: Function, beforeRemove: Function, onRemove: { type: Function, default: noop }, onChange: { type: Function, default: noop }, onPreview: { type: Function }, onSuccess: { type: Function, default: noop }, onProgress: { type: Function, default: noop }, onError: { type: Function, default: noop }, fileList: { type: Array, default() { return []; } }, autoUpload: { type: Boolean, default: true }, listType: { type: String, default: 'text' // text,picture,picture-card }, httpRequest: Function, disabled: Boolean, limit: Number, onExceed: { type: Function, default: noop } }, data() { return { uploadFiles: [], dragOver: false, draging: false, tempIndex: 1 }; }, computed: { uploadDisabled() { return this.disabled || (this.elForm || {}).disabled; } }, watch: { listType(type) { if (type === 'picture-card' || type === 'picture') { this.uploadFiles = this.uploadFiles.map(file => { if (!file.url && file.raw) { try { file.url = URL.createObjectURL(file.raw); } catch (err) { console.error('[Element Error][Upload]', err); } } return file; }); } }, fileList: { immediate: true, handler(fileList) { this.uploadFiles = fileList.map(item => { item.uid = item.uid || (Date.now() + this.tempIndex++); item.status = item.status || 'success'; return item; }); } } }, methods: { handleStart(rawFile) { rawFile.uid = Date.now() + this.tempIndex++; let file = { status: 'ready', name: rawFile.name, size: rawFile.size, percentage: 0, uid: rawFile.uid, raw: rawFile }; if (this.listType === 'picture-card' || this.listType === 'picture') { try { file.url = URL.createObjectURL(rawFile); } catch (err) { console.error('[Element Error][Upload]', err); return; } } this.uploadFiles.push(file); this.onChange(file, this.uploadFiles); }, handleProgress(ev, rawFile) { const file = this.getFile(rawFile); this.onProgress(ev, file, this.uploadFiles); file.status = 'uploading'; file.percentage = ev.percent || 0; }, handleSuccess(res, rawFile) { const file = this.getFile(rawFile); if (file) { file.status = 'success'; file.response = res; this.onSuccess(res, file, this.uploadFiles); this.onChange(file, this.uploadFiles); } }, handleError(err, rawFile) { const file = this.getFile(rawFile); const fileList = this.uploadFiles; file.status = 'fail'; fileList.splice(fileList.indexOf(file), 1); this.onError(err, file, this.uploadFiles); this.onChange(file, this.uploadFiles); }, handleRemove(file, raw) { if (raw) { file = this.getFile(raw); } let doRemove = () => { this.abort(file); let fileList = this.uploadFiles; fileList.splice(fileList.indexOf(file), 1); this.onRemove(file, fileList); }; if (!this.beforeRemove) { doRemove(); } else if (typeof this.beforeRemove === 'function') { const before = this.beforeRemove(file, this.uploadFiles); if (before && before.then) { before.then(() => { doRemove(); }, noop); } else if (before !== false) { doRemove(); } } }, getFile(rawFile) { let fileList = this.uploadFiles; let target; fileList.every(item => { target = rawFile.uid === item.uid ? item : null; return !target; }); return target; }, abort(file) { this.$refs['upload-inner'].abort(file); }, clearFiles() { this.uploadFiles = []; }, submit() { this.uploadFiles .filter(file => file.status === 'ready') .forEach(file => { this.$refs['upload-inner'].upload(file.raw); }); }, getMigratingConfig() { return { props: { 'default-file-list': 'default-file-list is renamed to file-list.', 'show-upload-list': 'show-upload-list is renamed to show-file-list.', 'thumbnail-mode': 'thumbnail-mode has been deprecated, you can implement the same effect according to this case: http://element.eleme.io/#/zh-CN/component/upload#yong-hu-tou-xiang-shang-chuan' } }; } }, beforeDestroy() { this.uploadFiles.forEach(file => { if (file.url && file.url.indexOf('blob:') === 0) { URL.revokeObjectURL(file.url); } }); }, render(h) { let uploadList; if (this.showFileList) { uploadList = ( <UploadList disabled={this.uploadDisabled} listType={this.listType} files={this.uploadFiles} on-remove={this.handleRemove} handlePreview={this.onPreview}> { (props) => { if (this.$scopedSlots.file) { return this.$scopedSlots.file({ file: props.file }); } } } </UploadList> ); } const uploadData = { props: { type: this.type, drag: this.drag, action: this.action, multiple: this.multiple, 'before-upload': this.beforeUpload, 'with-credentials': this.withCredentials, headers: this.headers, name: this.name, data: this.data, accept: this.accept, fileList: this.uploadFiles, autoUpload: this.autoUpload, listType: this.listType, disabled: this.uploadDisabled, limit: this.limit, 'on-exceed': this.onExceed, 'on-start': this.handleStart, 'on-progress': this.handleProgress, 'on-success': this.handleSuccess, 'on-error': this.handleError, 'on-preview': this.onPreview, 'on-remove': this.handleRemove, 'http-request': this.httpRequest }, ref: 'upload-inner' }; const trigger = this.$slots.trigger || this.$slots.default; const uploadComponent = <upload {...uploadData}>{trigger}</upload>; return ( <div> { this.listType === 'picture-card' ? uploadList : ''} { this.$slots.trigger ? [uploadComponent, this.$slots.default] : uploadComponent } {this.$slots.tip} { this.listType !== 'picture-card' ? uploadList : ''} </div> ); } }; </script>