#今天用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 = bytes
let unitIndex = 0
while (size >= 1024 && unitIndex < units.length -1){
size /= 1024
unitIndex++;
}
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和原本对应文件的链接