Back

Comment créer une barre de progression de téléversement avec JavaScript

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();
  }
});

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és
  • event.total : Taille totale du fichier en octets
  • event.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.

OpenReplay