8.2 KiB
8.2 KiB
title, date
| title | date |
|---|---|
| Element Plus 上传器 | 2026-01-29 |
一、上传图片
<template>
<el-upload
v-model:file-list="imageFileList"
list-type="picture-card"
:on-preview="handlePreview"
:limit="3"
:before-upload="beforeUpload"
:http-request="httpRequest"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-icon><Plus /></el-icon>
<template #tip>
<div class="el-upload__tip">
请上传小于10M的图片
</div>
</template>
<el-dialog v-model="dialogVisible">
<el-image :src="dialogImageUrl" alt="Preview Image" />
</el-dialog>
</el-upload>
</template>
<script lang="ts" setup>
import { Plus } from '@element-plus/icons-vue'
import { onMounted, ref } from 'vue'
import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
import type { UploadRequestOptions } from 'element-plus'
import type { UploadProps, UploadUserFile, UploadRawFile } from 'element-plus'
import { getFileExtension, getFileHashName, validateImage } from '@/utils/file.ts'
import { uploadFileApi } from '@/apis/file.ts'
const imageFileList = ref<UploadUserFile[]>([])
const dialogImageUrl = ref('')
const dialogVisible = ref(false)
const baseUrl = ''
const apiImageList = [] as string[]
onMounted(async () => {
imageFileList.value = []
// 根据后端传来的List数据将信息添加文件列表中
apiImageList.forEach((item, index) => {
imageFileList.value.push({
name: index.toString(),
url: `${baseUrl}${item}`
})
})
})
const beforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
const maxFileMax = 1024 * 1024 * 10
const fileType = rawFile.type
const fileName = rawFile.name
const fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
if (!validateImage(fileType, fileExtension)) {
ElMessage.error('请上传图片')
return false
}
if (rawFile.size > maxFileMax) {
ElMessage.error('请上传10M以内的文件!')
return false
}
return true
}
const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
const loading = ElLoading.service({
lock: true,
text: '文件上传中 请等待',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
// 重命名文件
const filePath = `${baseUrl}/${getFileHashName(options.file.name)}.${getFileExtension(options.file.name)}`
const data = new FormData()
data.append('file', options.file)
data.append('filePath', filePath)
// 调用后端接口上传文件
await uploadFileApi(data)
apiImageList.push(filePath)
ElMessage.success('上传成功')
} catch (error) {
console.log(error)
ElMessage.error('上传失败 请联系管理员')
} finally {
loading.close()
}
}
const handleExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('最多上传3张图片')
}
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
const index = imageFileList.value.findIndex((item) => item.uid === uploadFile.uid)
apiImageList.splice(index, 1)
}
const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
dialogImageUrl.value = uploadFile.url!
dialogVisible.value = true
}
const beforeRemove: UploadProps['beforeRemove'] = () => {
return ElMessageBox.confirm('确认删除该文件?').then(() => true, () => false)
}
</script>
二、上传视频
<template>
<el-upload
v-model:file-list="videoFileList"
:limit="1"
:before-upload="beforeUpload"
:http-request="httpRequest"
:on-exceed="handleExceed"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-button type="primary">点击上传</el-button>
<template #tip>
<div class="el-upload__tip">
请上传小于200M的视频
</div>
</template>
</el-upload>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { ElLoading, ElMessage, ElMessageBox } from 'element-plus'
import type { UploadRequestOptions } from 'element-plus'
import type { UploadProps, UploadUserFile, UploadRawFile } from 'element-plus'
import { getFileExtension, getFileHashName, validateVideo } from '@/utils/file.ts'
import { uploadFileApi } from '@/apis/file.ts'
const videoFileList = ref<UploadUserFile[]>([])
let baseUrl = ''
const apiVideoUrl = ''
onMounted(async () => {
videoFileList.value = []
if (apiVideoUrl) {
videoFileList.value.push({
name: 'video',
url: `${baseUrl}p/${apiVideoUrl}`
})
}
})
const beforeUpload: UploadProps['beforeUpload'] = (rawFile: UploadRawFile) => {
const maxFileMax = 1024 * 1024 * 200
const fileType = rawFile.type
const fileName = rawFile.name
const fileExtension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
if (!validateVideo(fileType, fileExtension)) {
ElMessage.error('请上传视频')
return false
}
if (rawFile.size > maxFileMax) {
ElMessage.error('请上传200M以内的文件!')
return false
}
return true
}
const httpRequest: UploadProps['httpRequest'] = async (options: UploadRequestOptions): Promise<any> => {
const loading = ElLoading.service({
lock: true,
text: '文件上传中 请等待',
background: 'rgba(0, 0, 0, 0.7)'
})
try {
const filePath = `${baseUrl}/${getFileHashName(options.file.name)}.${getFileExtension(options.file.name)}`
const data = new FormData()
data.append('file', options.file)
data.append('filePath', filePath)
await uploadFileApi(data)
baseUrl = filePath
ElMessage.success('上传成功')
} catch (error) {
console.log(error)
ElMessage.error('上传失败 请联系管理员')
} finally {
loading.close()
}
}
const handleExceed: UploadProps['onExceed'] = () => {
ElMessage.warning('最多上传1个视频')
}
const beforeRemove: UploadProps['beforeRemove'] = () => {
return ElMessageBox.confirm('确认删除该文件?').then(() => true, () => false)
}
const handleRemove: UploadProps['onRemove'] = () => {
baseUrl = ''
}
</script>
三、工具类
import { hashSHA256 } from 'vue3-common/utils/cryptoUtil'
export const getFileHashName = (name: string) => {
return hashSHA256(name)
}
export const getFileExtension = (name: string) => {
return name.substring(name.lastIndexOf('.') + 1).toLowerCase()
}
export const validateExcel = (fileType: string, fileExtension: string): boolean => {
// 常见的 Excel MIME 类型
const excelMimeTypes = [
'application/vnd.ms-excel', // .xls
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // .xlsx
'application/vnd.ms-excel.sheet.macroEnabled.12', // .xlsm
'text/csv' // CSV
]
// 常见的 Excel 文件扩展名
const excelExtensions = ['xls', 'xlsx', 'xlsm', 'csv']
return excelMimeTypes.includes(fileType) || excelExtensions.includes(fileExtension.toLowerCase())
}
export const validateImage = (fileType: string, fileExtension: string): boolean => {
// 常见的图片 MIME 类型
const imageMimeTypes = [
'image/jpeg', // JPEG
'image/jpg', // JPG
'image/png', // PNG
'image/gif', // GIF
'image/bmp', // BMP
'image/webp', // WebP
'image/svg+xml' // SVG
]
// 常见的图片文件扩展名
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
return imageMimeTypes.includes(fileType) || imageExtensions.includes(fileExtension.toLowerCase())
}
export const validateVideo = (fileType: string, fileExtension: string): boolean => {
// 常见的视频 MIME 类型
const videoMimeTypes = [
'video/mp4', // MP4
'video/mpeg', // MPEG
'video/quicktime', // MOV
'video/x-msvideo', // AVI
'video/x-matroska', // MKV
'video/webm', // WebM
'video/3gpp', // 3GP
'video/3gpp2', // 3G2
'video/x-flv', // FLV
'video/mp2t', // TS (MPEG Transport Stream)
'application/x-mpegURL', // M3U8 (HLS)
'video/H264', // H264
'video/H265' // H265/HEVC
]
// 常见的视频文件扩展名
const videoExtensions = [
'mp4',
'mpeg',
'mpg',
'mov',
'avi',
'mkv',
'webm',
'3gp',
'3g2',
'flv',
'ts',
'm3u8',
'h264',
'h265',
'hevc'
]
return videoMimeTypes.includes(fileType) || videoExtensions.includes(fileExtension.toLowerCase())
}