UNPKG

element-plus

Version:

A Component Library for Vue 3

180 lines (164 loc) 4.47 kB
import { ref, watch } from 'vue' import { NOOP } from '@vue/shared' import cloneDeep from 'lodash/cloneDeep' // Inline types import type { ListType, UploadFile, UploadStatus, ElFile, ElUploadProgressEvent, IUseHandlersProps, } from './upload.type' type UploadRef = { abort: (file: UploadFile) => void upload: (file: ElFile) => void } // helpers function getFile(rawFile: ElFile, uploadFiles: UploadFile[]) { return uploadFiles.find((file) => file.uid === rawFile.uid) } function genUid(seed: number) { return Date.now() + seed } export default (props: IUseHandlersProps) => { const uploadFiles = ref<UploadFile[]>([]) const uploadRef = ref<UploadRef>(null) let tempIndex = 1 function abort(file: UploadFile) { uploadRef.value.abort(file) } function clearFiles(status: UploadStatus[] = ['success', 'fail']) { uploadFiles.value = uploadFiles.value.filter((row) => { return status.indexOf(row.status) === -1 }) } function handleError(err: Error, rawFile: ElFile) { const file = getFile(rawFile, uploadFiles.value) file.status = 'fail' uploadFiles.value.splice(uploadFiles.value.indexOf(file), 1) props.onError(err, file, uploadFiles.value) props.onChange(file, uploadFiles.value) } function handleProgress(ev: ElUploadProgressEvent, rawFile: ElFile) { const file = getFile(rawFile, uploadFiles.value) props.onProgress(ev, file, uploadFiles.value) file.status = 'uploading' file.percentage = ev.percent || 0 } function handleSuccess(res: any, rawFile: ElFile) { const file = getFile(rawFile, uploadFiles.value) if (file) { file.status = 'success' file.response = res props.onSuccess(res, file, uploadFiles.value) props.onChange(file, uploadFiles.value) } } function handleStart(rawFile: ElFile) { const uid = genUid(tempIndex++) rawFile.uid = uid const file: UploadFile = { name: rawFile.name, percentage: 0, status: 'ready', size: rawFile.size, raw: rawFile, uid, } if (props.listType === 'picture-card' || props.listType === 'picture') { try { file.url = URL.createObjectURL(rawFile) } catch (err) { console.error('[Element Error][Upload]', err) props.onError(err, file, uploadFiles.value) } } uploadFiles.value.push(file) props.onChange(file, uploadFiles.value) } function handleRemove(file: UploadFile, raw: ElFile) { if (raw) { file = getFile(raw, uploadFiles.value) } const revokeObjectURL = () => { if (file.url && file.url.indexOf('blob:') === 0) { URL.revokeObjectURL(file.url) } } const doRemove = () => { abort(file) const fileList = uploadFiles.value fileList.splice(fileList.indexOf(file), 1) props.onRemove(file, fileList) revokeObjectURL() } if (!props.beforeRemove) { doRemove() } else if (typeof props.beforeRemove === 'function') { const before = props.beforeRemove(file, uploadFiles.value) if (before instanceof Promise) { before .then(() => { doRemove() }) .catch(NOOP) } else if (before !== false) { doRemove() } } } function submit() { uploadFiles.value .filter((file) => file.status === 'ready') .forEach((file) => { uploadRef.value.upload(file.raw) }) } watch( () => props.listType, (val: ListType) => { if (val === 'picture-card' || val === 'picture') { uploadFiles.value = uploadFiles.value.map((file) => { if (!file.url && file.raw) { try { file.url = URL.createObjectURL(file.raw) } catch (err) { props.onError(err, file, uploadFiles.value) } } return file }) } } ) watch( () => props.fileList, (fileList: UploadFile[]) => { uploadFiles.value = fileList.map((file) => { const cloneFile = cloneDeep(file) return { ...cloneFile, uid: file.uid || genUid(tempIndex++), status: file.status || 'success', } }) }, { immediate: true, deep: true, } ) return { abort, clearFiles, handleError, handleProgress, handleStart, handleSuccess, handleRemove, submit, uploadFiles, uploadRef, } }