下面是代码:
<template>
<div>
<!-- uploadUrl 指定上传地址 -->
<!-- data 传递 CSRF token -->
<!-- fileList 已经选择的文件列表 -->
<!-- handleExceed 超过限制数量时的操作 -->
<!-- handleBeforeUpload 开始上传前的操作 -->
<!-- handleProgress 上传中的操作 -->
<!-- handleSuccess 上传成功后的操作 -->
<!-- handleError 上传失败后的操作 -->
<!-- auto-upload 禁用自动上传 -->
<!-- disable-remove 是否禁用删除按钮 -->
<!-- show-file-list 是否显示文件列表 -->
<el-upload
class="upload-demo"
ref="fileInput"
:action="uploadUrl"
:data="{ _token: csrfToken }"
:file-list="fileList"
:on-exceed="handleExceed"
:before-upload="handleBeforeUpload"
:on-progress="handleProgress"
:on-success="handleSuccess"
:on-error="handleError"
:auto-upload="false"
:disable-remove="uploading || fileList.length === 0"
:show-file-list="false"
>
<!-- disabled 是否禁用添加按钮 -->
<el-button slot="trigger" :disabled="!canAddFile || uploading" icon="el-icon-upload" size="small">{{
buttonText
}}</el-button>
<div v-if="error" class="error-message">{{ error }}</div>
<!-- 显示错误信息 -->
</el-upload>
<!-- 遍历已经选择的文件列表并展示 -->
<div v-for="item in fileList" :key="item.uid" class="file-item">
<div class="file-info">
<span>{{ item.name }}</span>
<span>({{ formatSize(item.size) }})</span>
<!-- 格式化文件大小 -->
</div>
<div class="file-actions">
<!-- 预览按钮,仅支持图片和视频类型 -->
<el-button
type="primary"
icon="el-icon-view"
@click.stop="previewFile(item)"
:disabled="!isImage(item)"
size="small"
></el-button>
<!-- 删除按钮 -->
<!-- uploading 是否正在上传 -->
<el-button
type="danger"
icon="el-icon-delete"
@click.stop="removeFile(item)"
:loading="uploading"
size="small"
></el-button>
</div>
</div>
<!-- 文件预览对话框 -->
<el-dialog :visible.sync="previewVisible" :append-to-body="true" :fullscreen="true" :show-close="false">
<img :src="previewUrl" v-if="isImage(previewUrl)" class="preview-image" />
<!-- 图片预览 -->
<video :src="previewUrl" v-else-if="isVideo(previewUrl)" controls class="preview-video"></video>
<!-- 视频预览 -->
</el-dialog>
<!-- 上传进度条 -->
<el-progress
v-if="uploading"
:percentage="uploadPercentage"
color="#409EFF"
text-inside
stroke-width="18"
style="margin-bottom: 10px"
></el-progress>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: {
uploadUrl: {
type: String,
required: true,
},
csrfToken: {
type: String,
required: true,
},
allowedFileTypes: {
type: Array,
default: () => ['image/jpeg', 'image/png', 'image/gif', 'video/mp4', 'video/webm', 'video/ogg'],
},
allowedFileSize: {
type: Number,
default: 5,
},
maxCount: {
type: Number,
default: 5,
},
buttonText: {
type: String,
default: '上传文件',
},
},
data() {
return {
fileList: [], // 已经选择的文件列表
uploading: false, // 是否正在上传
error: null, // 错误信息
previewVisible: false, // 预览对话框是否可见
previewUrl: null, // 当前预览的文件 URL
uploadPercentage: 0, // 上传进度百分比
}
},
computed: {
canAddFile() {
// 计算属性:是否可以添加新的文件
return this.fileList.length < this.maxCount
},
},
methods: {
handleExceed(files) {
// 超出限制数量时的操作
this.$message.warning(`最多只能上传 ${this.maxCount} 个文件`)
},
handleBeforeUpload(file) {
// 开始上传前的操作
if (!this.isAllowedFileType(file)) {
this.$message.error('不支持的文件类型')
return false
}
if (!this.isAllowedFileSize(file)) {
this.$message.error(`文件大小不能超过 ${this.allowedFileSize} MB`)
return false
}
const formData = new FormData()
formData.append('file', file)
formData.append('_token', this.csrfToken)
axios
.post(this.uploadUrl, formData, {
onUploadProgress: (progressEvent) => {
this.uploadPercentage = Math.floor((progressEvent.loaded / progressEvent.total) * 100)
},
})
.then((response) => {
this.handleSuccess(response.data.url, file)
})
.catch((error) => {
this.handleError(error)
})
this.uploadPercentage = 0 // 重置上传进度
this.uploading = true // 开始上传
return true
},
handleSuccess(response, file) {
// 上传成功后的操作
this.fileList.push({
uid: file.uid,
name: file.name,
size: file.size,
url: response.url,
})
this.error = null
this.uploading = false
},
handleError(error) {
// 上传失败后的操作
this.error = error.message
this.uploading = false
this.uploadPercentage = 0 // 重置上传进度
},
handlePreview(file) {
// 点击预览按钮后的操作
this.previewUrl = file.url
this.previewVisible = true
},
removeFile(file) {
// 点击删除按钮后的操作
const index = this.fileList.indexOf(file)
this.fileList.splice(index, 1)
},
isAllowedFileType(file) {
// 检查文件类型是否在允许的范围内
return this.allowedFileTypes.includes(file.type)
},
isAllowedFileSize(file) {
// 检查文件大小是否在允许的范围内
return file.size / 1024 / 1024 < this.allowedFileSize
},
isImage(file) {
// 检查文件是否为图片
return file.type.startsWith('image/')
},
isVideo(file) {
// 检查文件是否为视频
return file.type.startsWith('video/')
},
previewFile(file) {
// 预览图片或视频
if (this.isImage(file) || this.isVideo(file)) {
this.handlePreview(file)
}
},
formatSize(size) {
// 格式化文件大小
const units = ['B', 'KB', 'MB', 'GB', 'TB']
let index = 0
while (size >= 1024 && index < units.length - 1) {
size /= 1024
index++
}
return `${size.toFixed(2)} ${units[index]}`
},
handleProgress(event, file, fileList) {
// 上传中的操作
this.uploadPercentage = Math.floor((event.loaded / event.total) * 100)
},
},
}
</script>
<style scoped>
.upload-demo {
margin-bottom: 20px;
}
.file-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px;
border: 1px solid #ebeef5;
margin-bottom: 10px;
background-color: #f9fafc;
border-radius: 4px;
}
.file-info {
display: flex;
align-items: center;
}
.file-info span:first-child {
margin-right: 10px;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-actions {
display: flex;
align-items: center;
}
.preview-image {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.preview-video {
width: 100%;
height: 100%;
object-fit: contain;
}
.error-message {
color: #f56c6c;
margin-bottom: 10px;
}
</style>
二:如果你想在其他页面使用该组件,可以按照以下步骤进行操作:
Upload.vue
文件,则可以使用以下代码来引入组件:import Upload from './Upload.vue';
其中,./Upload.vue
是上传组件的路径,具体路径需要根据实际情况进行调整。
2. 注册组件
引入组件后,需要将其注册为当前页面的局部组件。可以在当前页面的 components
选项中进行注册,例如:
export default {
name: 'MyPage',
components: {
Upload,
},
}
这里将上传组件命名为 Upload
,并将其注册为 MyPage
组件的局部组件。
3. 使用组件
完成注册后,就可以在当前页面的模板中使用上传组件了。例如:
<template>
<div>
<upload :upload-url="uploadUrl" :csrf-token="csrfToken" />
div>
template>
<script>
import Upload from './Upload.vue';
export default {
components: { Upload },
data() {
return {
uploadUrl: '/api/upload',
csrfToken: '...',//可以从 cookie 中读取这个 CSRF token,并将其作为参数传递给服务器。
};
},
// ...
};
script>
在上面的代码中,我们将
组件作为一个子组件插入到当前页面中,并传递了两个属性:upload-url
和 csrf-token
。其中,upload-url
指定了上传文件的接口地址,而 csrf-token
则是用于防止跨站请求伪造攻击的 CSRF token。需要根据具体的业务需求设置这两个属性。
总结:以上代码我没有在项目中运行 如有问题可以私信我,然后再做优化。