import { createNamespace, addUnit, noop } from '../utils'; import { toArray, readFile, isOversize, isImageFile } from './utils'; import Icon from '../icon'; import Image from '../image'; import ImagePreview from '../image-preview'; const [createComponent, bem] = createNamespace('uploader'); export default createComponent({ inheritAttrs: false, model: { prop: 'fileList' }, props: { disabled: Boolean, uploadText: String, afterRead: Function, beforeRead: Function, beforeDelete: Function, previewSize: [Number, String], name: { type: [Number, String], default: '' }, accept: { type: String, default: 'image/*' }, fileList: { type: Array, default: () => [] }, maxSize: { type: Number, default: Number.MAX_VALUE }, maxCount: { type: Number, default: Number.MAX_VALUE }, previewImage: { type: Boolean, default: true }, resultType: { type: String, default: 'dataUrl' } }, computed: { detail() { return { name: this.name }; }, previewSizeWithUnit() { return addUnit(this.previewSize); } }, methods: { onChange(event) { let { files } = event.target; if (this.disabled || !files.length) { return; } files = files.length === 1 ? files[0] : [].slice.call(files); if (this.beforeRead) { const response = this.beforeRead(files, this.detail); if (!response) { this.resetInput(); return; } if (response.then) { response .then(() => { this.readFile(files); }) .catch(this.resetInput); return; } } this.readFile(files); }, readFile(files) { const oversize = isOversize(files, this.maxSize); if (Array.isArray(files)) { const maxCount = this.maxCount - this.fileList.length; if (files.length > maxCount) { files = files.slice(0, maxCount); } Promise.all(files.map(file => readFile(file, this.resultType))).then(contents => { const fileList = files.map((file, index) => ({ file, content: contents[index] })); this.onAfterRead(fileList, oversize); }); } else { readFile(files, this.resultType).then(content => { this.onAfterRead({ file: files, content }, oversize); }); } }, onAfterRead(files, oversize) { if (oversize) { this.$emit('oversize', files, this.detail); return; } this.resetInput(); this.$emit('input', [...this.fileList, ...toArray(files)]); if (this.afterRead) { this.afterRead(files, this.detail); } }, onDelete(file, index) { if (this.beforeDelete) { const response = this.beforeDelete(file, this.detail); if (!response) { return; } if (response.then) { response .then(() => { this.deleteFile(file, index); }) .catch(noop); return; } } this.deleteFile(file, index); }, deleteFile(file, index) { const fileList = this.fileList.slice(0); fileList.splice(index, 1); this.$emit('input', fileList); this.$emit('delete', file); }, resetInput() { /* istanbul ignore else */ if (this.$refs.input) { this.$refs.input.value = ''; } }, onPreviewImage(item) { const imageFiles = this.fileList .filter(item => isImageFile(item)) .map(item => item.content || item.url); ImagePreview({ images: imageFiles, closeOnPopstate: true, startPosition: imageFiles.indexOf(item.content || item.url) }); }, renderPreview() { if (!this.previewImage) { return; } return this.fileList.map((item, index) => (
{isImageFile(item) ? ( { this.onPreviewImage(item); }} /> ) : (
{item.file ? item.file.name : item.url}
)} { this.onDelete(item, index); }} />
)); }, renderUpload() { if (this.fileList.length >= this.maxCount) { return; } const slot = this.slots(); const Input = ( ); if (slot) { return (
{slot} {Input}
); } let style; if (this.previewSize) { const size = this.previewSizeWithUnit; style = { width: size, height: size }; } return (
{this.uploadText && {this.uploadText}} {Input}
); } }, render() { return (
{this.renderPreview()} {this.renderUpload()}
); } });