import { use, suffixPx } from '../utils'; import Icon from '../icon'; import Image from '../image'; const [sfc, bem] = use('uploader'); export default sfc({ inheritAttrs: false, props: { preview: Boolean, disabled: Boolean, uploadText: String, afterRead: Function, beforeRead: Function, previewSize: [Number, String], accept: { type: String, default: 'image/*' }, resultType: { type: String, default: 'dataUrl' }, maxSize: { type: Number, default: Number.MAX_VALUE }, maxCount: { type: Number, default: Number.MAX_VALUE } }, data() { return { uploadedFiles: [] }; }, computed: { detail() { return { name: this.$attrs.name || '' }; } }, methods: { onChange(event) { let { files } = event.target; if (this.disabled || !files.length) { return; } files = files.length === 1 ? files[0] : [].slice.call(files, 0); if (!files || (this.beforeRead && !this.beforeRead(files, this.detail))) { this.resetInput(); return; } if (Array.isArray(files)) { const maxCount = this.maxCount - this.uploadedFiles.length; files = files.slice(0, maxCount); Promise.all(files.map(this.readFile)).then(contents => { let oversize = false; const payload = files.map((file, index) => { if (file.size > this.maxSize) { oversize = true; } return { file: files[index], content: contents[index] }; }); this.onAfterRead(payload, oversize); }); } else { this.readFile(files).then(content => { this.onAfterRead({ file: files, content }, files.size > this.maxSize); }); } }, readFile(file) { return new Promise(resolve => { const reader = new FileReader(); reader.onload = event => { resolve(event.target.result); }; if (this.resultType === 'dataUrl') { reader.readAsDataURL(file); } else if (this.resultType === 'text') { reader.readAsText(file); } }); }, onAfterRead(files, oversize) { if (oversize) { this.$emit('oversize', files, this.detail); return; } if (Array.isArray(files)) { files.forEach(this.addPreviewImage); } else { this.addPreviewImage(files); } if (this.afterRead) { this.afterRead(files, this.detail); } this.resetInput(); }, addPreviewImage(file) { this.uploadedFiles.push(file); }, resetInput() { /* istanbul ignore else */ if (this.$refs.input) { this.$refs.input.value = ''; } }, renderPreview() { if (this.preview) { return this.uploadedFiles.map(file => ( <Image fit="cover" class={bem('preview')} src={file.content} width={this.previewSize} height={this.previewSize} /> )); } }, renderUpload() { if (this.uploadedFiles.length >= this.maxCount) { return; } const slot = this.slots(); const Input = ( <input {...{ attrs: this.$attrs }} ref="input" type="file" accept={this.accept} class={bem('input')} disabled={this.disabled} onChange={this.onChange} /> ); if (slot) { return ( <div class={bem('input-wrapper')}> {slot} {Input} </div> ); } let style; if (this.previewSize) { const size = suffixPx(this.previewSize); style = { width: size, height: size }; } return ( <div class={bem('upload')} style={style}> <Icon name="plus" class={bem('upload-icon')} /> {this.uploadText && <span class={bem('upload-text')}>{this.uploadText}</span>} {Input} </div> ); } }, render(h) { return ( <div class={bem()}> <div class={bem('wrapper')}> {this.renderPreview()} {this.renderUpload()} </div> </div> ); } });