Core Implementation Strategy
The key to customizing the upload behavior is utilizing the :http-request prop, which overrrides the default upload mechanism:
<el-upload
:http-request="handleCustomUpload"
:auto-upload="false"
multiple
accept=".jpg,.png,.gif"
>
<el-button type="primary">Select Images</el-button>
<el-button type="success" @click="triggerUpload">Upload Selected</el-button>
</el-upload>
FormData Preparation
With in your custom upload handler, prepare the FormData object with the selected file:
handleCustomUpload(uploadParams) {
const payload = new FormData();
const selectedFile = uploadParams.file;
payload.append("imageData", selectedFile);
this.executeUploadRequest(payload);
}
Complete Implementation Example
<template>
<div class="upload-container">
<el-upload
ref="imageUploader"
class="custom-uploader"
action="#"
:auto-upload="false"
:multiple="true"
:before-upload="validateFile"
:http-request="processUpload"
:on-error="handleUploadFailure"
:on-success="handleUploadSuccess"
accept="image/*"
>
<el-button slot="trigger" type="primary">Choose Images</el-button>
<el-button
class="upload-button"
type="success"
@click="initiateUpload"
>
Start Upload
</el-button>
<div slot="tip" class="upload-tip">
Supports JPG, PNG, GIF formats. Maximum size per file: 5MB
</div>
</el-upload>
</div>
</template>
<script>
import apiService from '@/services/api';
export default {
name: 'ImageUploadComponent',
data() {
return {
uploadEndpoint: '/api/images/upload'
};
},
computed: {
currentUser() {
return JSON.parse(localStorage.getItem('userData'));
}
},
methods: {
async processUpload(uploadObject) {
try {
const formData = new FormData();
const file = uploadObject.file;
formData.append('file', file);
formData.append('userId', this.currentUser.id);
const response = await apiService.post(this.uploadEndpoint, formData, {
headers: {
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${this.currentUser.token}`
},
onUploadProgress: progressEvent => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
this.updateProgress(percentCompleted);
}
});
this.showSuccessNotification('Image uploaded successfully');
return response.data;
} catch (error) {
this.handleError(error);
throw error;
}
},
validateFile(file) {
const validFormats = ['image/jpeg', 'image/png', 'image/gif'];
const isValidFormat = validFormats.includes(file.type);
const isValidSize = file.size / 1024 / 1024 < 5;
if (!isValidFormat) {
this.$message.error('Invalid file format. Please select JPG, PNG, or GIF.');
return false;
}
if (!isValidSize) {
this.$message.error('File size exceeds 5MB limit.');
return false;
}
return true;
},
handleUploadSuccess(response, file, fileList) {
console.log('Upload completed:', response);
this.$message({
message: 'File uploaded successfully',
type: 'success',
duration: 3000
});
},
handleUploadFailure(error, file, fileList) {
const errorMessage = error.response?.data?.message || 'Upload failed';
this.$message.error(errorMessage);
},
initiateUpload() {
this.$refs.imageUploader.submit();
},
updateProgress(percentage) {
// Implement progress bar update logic
},
showSuccessNotification(message) {
this.$notify({
title: 'Success',
message,
type: 'success',
position: 'top-right'
});
},
handleError(error) {
if (error.response?.status === 401) {
this.$message.warning('Session expired. Please login again.');
this.$router.push('/login');
} else {
this.$message.error(error.response?.data?.message || 'Upload failed');
}
}
}
};
</script>
<style scoped>
.upload-container {
padding: 20px;
max-width: 600px;
margin: 0 auto;
}
.custom-uploader {
display: flex;
flex-direction: column;
align-items: center;
}
.upload-button {
margin-left: 10px;
}
.upload-tip {
font-size: 12px;
color: #606266;
margin-top: 7px;
}
</style>