<template>
<div class="container">
<button @click="addUploadArea" class="add-button">+ 添加上传区域</button>
<div v-for="(area, index) in areas" :key="area.id" class="upload-area">
<div class="header">
<h3>上传区域 {{ index + 1 }}</h3>
<button @click="removeUploadArea(index)" class="remove-button">×</button>
</div>
<!-- 点击上传区域 -->
<div class="upload-wrapper">
<!-- 隐藏的 input 元素 -->
<input
type="file"
ref="fileInputs"
:id="'file-input-' + index"
class="hidden-input"
accept="image/*"
@change="(e) => handleFileSelect(e, index)"
/>
<!-- 可视化的上传区域 -->
<label
:for="'file-input-' + index"
class="upload-box"
@dragover.prevent
@drop.prevent="(e) => handleDrop(e, index)"
>
<div class="upload-content">
<div class="upload-icon">📁</div>
<div class="upload-text">
<p>点击选择文件 或 拖拽文件到这里</p>
<p>支持格式: JPEG, PNG (最大5MB)</p>
</div>
</div>
</label>
</div>
<!-- 上传状态和预览 -->
<div v-if="area.uploading" class="status">上传中...</div>
<div v-if="area.error" class="error">{{ area.error }}</div>
<img v-if="area.previewUrl" :src="area.previewUrl" class="preview-image" />
</div>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import axios from 'axios'
// 生成唯一ID
let idCounter = 0
const generateId = () => idCounter++
// 上传区域数据
const areas = ref([])
const fileInputs = ref([]) // 用于操作隐藏的 input 元素
// 默认区域配置
const defaultArea = () => ({
id: generateId(),
uploading: false,
previewUrl: '',
error: ''
})
// 初始化一个默认区域
areas.value.push(defaultArea())
// 添加新区域
const addUploadArea = () => {
areas.value.push(defaultArea())
}
// 删除区域
const removeUploadArea = (index) => {
areas.value.splice(index, 1)
}
// 处理文件选择(点击上传)
const handleFileSelect = (event, areaIndex) => {
const files = event.target.files
if (files.length > 0) {
processFiles(files, areaIndex)
event.target.value = '' // 清空 input 以便重复上传
}
}
// 处理拖放事件
const handleDrop = (event, areaIndex) => {
const dt = event.dataTransfer
processFiles(dt.files, areaIndex)
}
// 统一处理文件(兼容点击、拖拽、粘贴)
const processFiles = async (files, areaIndex) => {
const area = areas.value[areaIndex]
// 重置状态
area.error = ''
area.previewUrl = ''
// 验证文件
const file = files[0]
if (!file) {
area.error = '未选择文件'
return
}
if (!file.type.startsWith('image/')) {
area.error = '仅支持图片文件 (JPEG, PNG)'
return
}
if (file.size > 5 * 1024 * 1024) {
area.error = '文件大小不能超过5MB'
return
}
// 显示预览
area.previewUrl = URL.createObjectURL(file)
// 开始上传
try {
area.uploading = true
const formData = new FormData()
formData.append('file', file)
const response = await axios.post('https://your-api.com/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' }
})
console.log('上传成功:', response.data)
// 这里可以处理服务器返回的URL
} catch (error) {
area.error = '上传失败: ' + (error.response?.data?.message || error.message)
} finally {
area.uploading = false
}
}
</script>
<style scoped>
.container {
max-width: 800px;
margin: 20px auto;
padding: 20px;
}
.add-button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
margin-bottom: 20px;
}
.upload-area {
border: 2px dashed #ccc;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
position: relative;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.remove-button {
background: #ff4444;
color: white;
border: none;
width: 24px;
height: 24px;
border-radius: 50%;
cursor: pointer;
}
/* 点击上传区域样式 */
.upload-wrapper {
position: relative;
}
.hidden-input {
display: none;
}
.upload-box {
display: block;
min-height: 150px;
padding: 20px;
background: #f8f8f8;
border-radius: 4px;
border: 2px dashed #ccc;
cursor: pointer;
transition: all 0.3s;
}
.upload-box:hover {
border-color: #4CAF50;
background: #f0fff4;
}
.upload-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
color: #666;
}
.upload-icon {
font-size: 40px;
margin-bottom: 10px;
}
.upload-text p {
margin: 5px 0;
text-align: center;
}
.preview-image {
max-width: 100%;
margin-top: 15px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.status {
color: #2196F3;
margin-top: 10px;
}
.error {
color: #ff4444;
margin-top: 10px;
}
</style>
拖拽和点击上传图片功能
最新推荐文章于 2025-05-24 13:45:11 发布