????????#今天用el-upload感到很多不方便,遂決定自己封裝一個。注:本文不提供表面的按鈕樣式和文件上傳成功后的樣式,需要自己創建。本文僅介紹邏輯函數#
1,準備幾個表面用來指引上傳的元素
2,創造統一的隱藏文件上傳輸入框,監聽文件改變函數來監聽文件的上傳
<input type="file"ref="fileInput" class="hidden" @change="handleFileUpload" :accept="currentFileType"
/>
你放在哪里都行,反正要隱藏起來,用來調用點擊事件
3,準備文件上傳的Ref和上傳成功的文件的數組,記得ref要綁定上面的輸入框
- 創造ref綁定輸入框,用于讀取上傳到文件相關信息
- 創建上傳數組用于存放上傳文件組合,有文件名字,文件類型,文件路徑(圖片和視頻才有),文件大小
// 文件上傳ref
const fileInput = ref<HTMLInputElement | null>(null)
// 上傳的文件列表
const uploadedFiles = reactive<{name: string;type: 'file' | 'image' | 'video';url?: string;size: string;
}[]>([]);
4,點擊表面的上傳按鈕時,調用隱藏的上傳輸入框的click事件
? ? ? ? 事件要綁定在上面的隱藏輸入框
const handleFile = () => {fileInput.value?.click()
}
5, 處理文件上傳函數
- ?如果文件數組為空則返回
- 檢查文件大小,如果為video視頻文件并且文件大小大于100MB同樣返回
- 確定文件類型,同樣使用startsWith函數
- 添加到文件上傳列表中,包含名字,類型,創造的url(視頻或圖片才有),大小(格式化函數返回)
- 最后清除文件上傳框
const handleFileUpload = (event: Event) => {const input = event.target as HTMLInputElement;if (!input.files || input.files.length === 0) {alert('您沒有上傳文件')return};Array.from(input.files).forEach(file => {// 檢查視頻文件大小if( file.type.startsWith('video/') && file.size > 100 * 1024 * 1024){alert(`視頻文件${file.name}太大, 請限制在100MB以內`);return}// 確定文件類型let fileType: 'file' | 'image' | 'video' = 'file';if (file.type.startsWith('image/')) {fileType = 'image';} else if (file.type.startsWith('video/')) {fileType = 'video';}// 添加到上傳列表uploadedFiles.push({name: file.name,type: fileType,url: fileType !== 'file' ? URL.createObjectURL(file) : undefined,size: formatFileSize(file.size)});alert(`已經添加:${file.name}`)})input.value = '';
}
6,格式化函數,用來計算文件大小,傳入函數為文件的大小,單位B
- 定義大小四個單位
- 循環計算哪個大小單位,每次除以1024
- 最后返回得到的size是除完后的結果,toFixed保留一位小數
const formatFileSize = (bytes: number): string => {const units = ['B', 'KB', 'MB', 'GB']let size = byteslet unitIndex = 0while (size >= 1024 && unitIndex < units.length -1){size /= 1024unitIndex++;}return `${size.toFixed(1)} ${units[unitIndex]}`
}
7, 刪除文件函數,需要綁定在刪除元素上
比如綁定在文件刪除按鈕,點擊時觸發,傳入文件數組的對應索引
- 如果對應文件存在URL路徑,需要統一肢解路徑,使用函數URL.revokeObjectURL(對應url字符串)
- splice根據索引刪除對應元素
const removeFile = (index:number) =>{if (uploadedFiles[index].url)URL.revokeObjectURL(uploadedFiles[index].url)uploadedFiles.splice(index, 1)alert.warning('已刪除文件')
}
8,清除函數,在組件銷毀前調用
同第七條,在組件關閉前調用URL.revokeObjectURL函數解放url,防止永遠無法復用
// 清理函數
const cleanupBlobUrls = () =>{uploadedFiles.forEach(file => {if (file.url)URL.revokeObjectURL(file.url)})
}
// 在組件銷毀前調用
onBeforeUnmount(() => {cleanupBlobUrls()
})
9,最后在HTML中自由渲染函數即可?
??補充:
-
startWith函數:
startsWith()用于
確定此字符串是否以指定字符串的字符開頭,并根據需要返回true
或false
- 輸入文件通過event.target.files去尋找,為上傳文件組成的數組,有type,name,size等屬性
- URL.createObjectURL()接受文件(比如圖片和視頻),創建URL一個字符串,是一串指向傳入文件的URL路徑。
- URL.revokeObjectURL()接受URL路徑,釋放URL和原本對應文件的鏈接