Comment créer une barre de progression de téléversement avec JavaScript
Le téléversement de fichiers sans retour visuel laisse les utilisateurs se demander si quelque chose se passe. Une barre de progression transforme cette incertitude en une expérience claire et accessible qui montre exactement quelle partie du téléversement est terminée.
Cet article démontre comment créer une barre de progression de téléversement en temps réel en utilisant l’API XMLHttpRequest de JavaScript, des éléments HTML sémantiques et les bonnes pratiques d’accessibilité—créant ainsi une solution qui fonctionne de manière fiable sur tous les navigateurs modernes.
Points clés à retenir
- XMLHttpRequest reste l’API standard pour suivre la progression du téléversement, car l’API Fetch ne prend pas en charge les événements de progression de téléversement
- Le HTML sémantique avec les attributs ARIA garantit l’accessibilité pour tous les utilisateurs
- La solution fonctionne sur tous les navigateurs modernes sans dépendances externes
- Une gestion appropriée des erreurs et des contrôles utilisateur créent une expérience de téléversement robuste
Mise en place de la structure HTML
Commencez avec du HTML sémantique qui fournit un retour visuel et accessible :
<form id="uploadForm">
<label for="fileInput">Select file to upload:</label>
<input type="file" id="fileInput" name="file" accept="image/*,application/pdf">
<progress id="uploadProgress" value="0" max="100" aria-label="Upload progress"></progress>
<span id="progressText" aria-live="polite">0% uploaded</span>
<button type="submit">Upload File</button>
<button type="button" id="cancelBtn" disabled>Cancel Upload</button>
</form>
L’élément <progress> fournit une sémantique native que les technologies d’assistance comprennent. Le pourcentage textuel qui l’accompagne garantit que les utilisateurs ne s’appuient pas uniquement sur des indices visuels. L’attribut aria-live="polite" annonce les changements de pourcentage aux lecteurs d’écran sans interrompre les autres contenus.
Pourquoi XMLHttpRequest pour la progression du téléversement
Bien que l’API Fetch gère la plupart des requêtes HTTP modernes de manière élégante, elle n’expose toujours pas les événements de progression de téléversement. L’objet XMLHttpRequest reste l’outil approprié pour suivre les implémentations de progression de téléversement car il fournit le gestionnaire d’événements xhr.upload.onprogress.
Notez que seul XMLHttpRequest synchrone est obsolète—XHR asynchrone reste une API de référence, bien prise en charge et parfaite pour ce cas d’usage.
Implémentation de la barre de progression de téléversement avec JavaScript
Voici l’implémentation complète qui gère la sélection de fichiers, le suivi du téléversement et les contrôles utilisateur :
const form = document.getElementById('uploadForm');
const fileInput = document.getElementById('fileInput');
const progressBar = document.getElementById('uploadProgress');
const progressText = document.getElementById('progressText');
const cancelBtn = document.getElementById('cancelBtn');
let currentXHR = null;
form.addEventListener('submit', (e) => {
e.preventDefault();
const file = fileInput.files[0];
if (!file) return;
// Validate file size (10MB limit example)
const maxSize = 10 * 1024 * 1024;
if (file.size > maxSize) {
alert('File size exceeds 10MB limit');
return;
}
uploadFile(file);
});
function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
currentXHR = new XMLHttpRequest();
// Track upload progress
currentXHR.upload.onprogress = (event) => {
if (event.lengthComputable) {
const percentComplete = Math.round((event.loaded / event.total) * 100);
updateProgress(percentComplete);
} else {
// Handle indeterminate progress
progressBar.removeAttribute('value');
progressText.textContent = 'Uploading...';
}
};
// Handle completion
currentXHR.onload = function() {
if (currentXHR.status === 200) {
updateProgress(100);
progressText.textContent = 'Upload complete!';
resetForm();
} else {
handleError('Upload failed: ' + currentXHR.statusText);
}
};
// Handle errors
currentXHR.onerror = () => handleError('Network error occurred');
currentXHR.onabort = () => handleError('Upload cancelled');
// Send request
currentXHR.open('POST', '/api/upload', true);
currentXHR.send(formData);
// Enable cancel button
cancelBtn.disabled = false;
}
function updateProgress(percent) {
progressBar.value = percent;
progressText.textContent = `${percent}% uploaded`;
}
function handleError(message) {
progressText.textContent = message;
progressBar.value = 0;
resetForm();
}
function resetForm() {
cancelBtn.disabled = true;
currentXHR = null;
setTimeout(() => {
progressBar.value = 0;
progressText.textContent = '0% uploaded';
}, 2000);
}
// Cancel upload functionality
cancelBtn.addEventListener('click', () => {
if (currentXHR) {
currentXHR.abort();
}
});
Discover how at OpenReplay.com.
Comprendre l’événement de progression
L’événement xhr.upload.onprogress fournit trois propriétés cruciales :
event.loaded: Octets déjà téléversésevent.total: Taille totale du fichier en octetsevent.lengthComputable: Booléen indiquant si la taille totale est connue
Lorsque lengthComputable est vrai, calculez le pourcentage comme (loaded / total) * 100. Lorsqu’il est faux, le serveur n’a pas fourni d’en-têtes Content-Length, donc affichez un état de progression indéterminé en supprimant l’attribut value de l’élément progress.
Stylisation pour une meilleure expérience utilisateur
Ajoutez du CSS pour rendre l’implémentation de la progression du téléversement visuellement claire :
progress {
width: 100%;
height: 24px;
margin: 10px 0;
}
/* Webkit browsers */
progress::-webkit-progress-bar {
background-color: #f0f0f0;
border-radius: 4px;
}
progress::-webkit-progress-value {
background-color: #4CAF50;
border-radius: 4px;
transition: width 0.3s ease;
}
/* Firefox */
progress::-moz-progress-bar {
background-color: #4CAF50;
border-radius: 4px;
}
#progressText {
display: block;
margin-top: 5px;
font-weight: 600;
}
Considérations côté serveur
Le point de terminaison du serveur doit accepter les téléversements multipart/form-data. Voici un exemple minimal Node.js utilisant Express et Multer :
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/api/upload', upload.single('file'), (req, res) => {
// File is available as req.file
res.json({ success: true, filename: req.file.filename });
});
Pour la production, ajoutez la validation du type de fichier, l’analyse antivirus et une gestion appropriée du stockage (système de fichiers local ou services cloud comme AWS S3).
Compatibilité des navigateurs et amélioration progressive
Cette approche fonctionne dans tous les navigateurs modernes car XMLHttpRequest Level 2 (qui inclut la progression du téléversement) est pris en charge depuis :
- Chrome 7+
- Firefox 3.5+
- Safari 5+
- Edge (toutes les versions)
Pour les navigateurs plus anciens, le téléversement fonctionne toujours—les utilisateurs ne verront simplement pas les mises à jour de progression. Le formulaire se dégrade gracieusement en un téléversement de fichier standard.
Conclusion
Créer une barre de progression de téléversement accessible nécessite XMLHttpRequest pour les événements de progression, du HTML sémantique pour la structure et du JavaScript réfléchi pour gérer les différents états de téléversement. Cette implémentation fournit un retour en temps réel qui fonctionne pour tous les utilisateurs, y compris ceux utilisant des technologies d’assistance, tout en maintenant une large compatibilité des navigateurs sans nécessiter de bibliothèques externes.
FAQ
L'API Fetch ne prend pas en charge les événements de progression de téléversement. XMLHttpRequest fournit le gestionnaire d'événements xhr.upload.onprogress spécifiquement pour suivre la progression du téléversement, ce qui en fait la seule option viable pour les barres de progression en temps réel.
Créez des instances XMLHttpRequest séparées pour chaque fichier ou mettez-les en file d'attente de manière séquentielle. Suivez la progression individuelle et calculez la progression globale en faisant la moyenne des pourcentages ou en additionnant les octets chargés sur tous les fichiers.
Sans en-têtes Content-Length, event.lengthComputable renvoie false. Affichez un état de progression indéterminé en supprimant l'attribut value de l'élément progress et en affichant un texte de chargement générique au lieu de pourcentages.
XMLHttpRequest standard ne prend pas en charge les téléversements reprenables. Pour cette fonctionnalité, implémentez des téléversements fragmentés avec prise en charge côté serveur ou utilisez des bibliothèques spécialisées qui gèrent la division de fichiers et la logique de reprise.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.