上传组件的封装
只有一部分,另一部分是在基础表单组件里只是个展示和上传没关系就不写了
<script>
export default {
name: 'BaseUpload',
}
</script>
<template>
<div>
<div
ref="uploadArea"
:class="{ 'upload-area': true, 'drop-active': isDrop }"
@dragover.prevent="dragover"
@drop.stop.prevent="handleDrop"
@click="openFileDialog"
@dragleave="onDragleave"
>
<input
type="file"
ref="fileInput"
hidden
@change="handleFileChange"
:multiple="multiple"
/>
<slot name="default">
<p>拖拽文件到这里,或点击选择文件</p>
</slot>
</div>
<div class="file-list">
<template v-for="(item, index) in fileList" :key="index">
<div v-if="checkFileType(item.url)" class="file-list-block">
<div class="file-list_close" @click="handleDelete(index)">
<el-icon size="16"><CircleClose /></el-icon>
</div>
<ImagePreview class="file-preview" :src="item.url"></ImagePreview>
</div>
<template v-else>
<el-tag
class="file-tag"
closable
type="primary"
@close="handleDelete(index)"
@click="handleClick(item)"
>
{{ item.name }}
</el-tag>
</template>
</template>
</div>
</div>
</template>
<script setup>
import { fileUpload } from '@/api/base/upload'
import ImagePreview from '@/components/ImagePreview'
const { proxy } = getCurrentInstance()
const emit = defineEmits(['upload-success', 'upload-error', 'upload-delete'])
const props = defineProps({
fileType: {
type: Array,
default: () => [],
},
formProp: {
type: String,
default: '',
},
multiple: {
type: Boolean,
default: false,
},
fileList: {
type: Array,
default: () => [],
},
})
let isDrop = ref(false)
let { fileType, formProp, fileList } = toRefs(props)
let imgType = ['png', 'jpeg', 'jpg', 'svg', 'gif']
const uploadArea = ref(null)
const fileInput = ref(null)
onMounted(() => {
// 初始化时聚焦文件输入框以支持键盘触发
fileInput.value.focus()
})
const openFileDialog = () => {
fileInput.value.click()
}
const handleFileChange = (e) => {
const files = e.target.files
if (files && files.length > 0) {
uploadFiles(files)
}
e.target.value = ''
}
const handleDrop = (e) => {
isDrop.value = false
const files = e.dataTransfer.files
if (files && files.length > 0) {
uploadFiles(files)
}
}
const uploadFiles = async (files) => {
let formData = new FormData()
let flag = beforeUpload(files)
if (!flag) {
proxy.$modal.msgError(
`文件格式不正确, 请上传${fileType.value.join('/')}格式文件!`
)
return
}
for (let file of files) {
formData.append('file', file)
}
fileUpload(formData)
.then((res) => {
let { data } = res
emit('upload-success', data, formProp.value) // 假设后端返回成功信息
})
.catch((err) => {
proxy.$modal.msgError(`上传失败${err}`)
emit('upload-error', formProp.value)
})
}
let dragover = () => {
isDrop.value = true
}
let onDragleave = () => {
isDrop.value = false
}
// 删除文件
let handleDelete = (index) => {
emit('upload-delete', index, formProp.value)
}
//预览文件
let handleClick = (item) => {
let link = document.createElement('a')
link.href = item.url
link.download = item.name
link.style.display = 'none'
document.body.appendChild(link)
link.textContent = item.name
link.setAttribute('target', '_black')
link.click()
link.remove()
}
function checkFileType(file) {
let fileExt = file.split('.')
let fileType = fileExt[fileExt.length - 1]
return imgType.includes(fileType)
}
function beforeUpload(files) {
let flag = true
if (files) {
for (let file of files) {
let fileName = file.name.split('.')
const fileExt = fileName[fileName.length - 1]
if (fileType.value.length && !fileType.value.includes(fileExt)) {
flag = false
}
}
}
return flag
}
</script>
<style scoped>
.upload-area {
border: 2px dashed #ccc;
padding: 20px;
text-align: center;
cursor: pointer;
}
.drop-active {
border-color: #0b6fee;
}
.file-list {
display: flex;
align-items: flex-start;
justify-content: flex-start;
margin-top: 10px;
column-gap: 10px;
}
.file-tag {
margin-bottom: 10px;
cursor: pointer;
}
.file-preview {
width: 60px;
height: 60px;
}
.file-list-block {
position: relative;
}
.file-list_close {
position: absolute;
top: -6px;
right: 0;
z-index: 1000;
}
</style>
效果图