12k
All articles

Comment ajouter la lecture vidéo dans une application Vue

Ajoutez la lecture vidéo aux apps Vue avec la vidéo HTML5 native, des composants réutilisables ou Video.js pour HLS, sous-titres, autoplay et nettoyage.

OpenReplay Team
OpenReplay Team
Comment ajouter la lecture vidéo dans une application Vue

Il existe trois façons d’ajouter la lecture vidéo à une application Vue, et le bon choix dépend du niveau de contrôle dont vous avez besoin : utilisez l’élément HTML5 natif <video> pour un simple clip intégré, tournez-vous vers Video.js lorsque vous avez besoin de streaming adaptatif, de sous-titres ou d’une large prise en charge des formats, et optez pour un composant prêt à l’emploi comme @videojs-player/vue si vous voulez les fonctionnalités de Video.js sans câbler le lecteur vous-même.

Le clip se lit généralement sans problème sur la machine sur laquelle vous l’avez développé. Puis un testeur ouvre la page sur un iPhone et la vidéo bascule en plein écran, ou bien la lecture automatique ne fait tout simplement rien dans Chrome sans que personne ne comprenne pourquoi. Ce guide parcourt donc les trois approches avec du code Vue 3 <script setup> prêt à copier-coller, et couvre les défaillances qui n’apparaissent que sur l’appareil de quelqu’un d’autre.

Points clés à retenir

  • Pour un simple clip intégré avec les contrôles par défaut, l’élément HTML5 natif <video> associé à :src, controls et poster ne nécessite aucune bibliothèque.
  • Dans Vue 3 avec <script setup>, récupérez l’élément via une template ref() et appelez l’API média native sur videoRef.value à l’intérieur de onMounted, jamais via document.querySelector.
  • Video.js s’affiche sans style si vous n’importez pas video.js/dist/video-js.css : c’est la raison la plus fréquente pour laquelle un lecteur Video.js dans Vue semble cassé.
  • Chaque fois que vous initialisez Video.js, appelez player.dispose() dans onBeforeUnmount (Vue 3). L’oublier provoque une fuite du lecteur et de son DOM à chaque démontage.
  • Les navigateurs bloquent la lecture automatique avec le son : pour une lecture automatique fiable, vous devez définir à la fois muted et autoplay, et ajouter playsinline pour qu’iOS Safari lise la vidéo en ligne au lieu de forcer le plein écran.

Comment choisir une approche de lecteur vidéo pour Vue ?

Choisissez <video> natif si vous n’avez besoin ni d’interface personnalisée ni de streaming adaptatif ; choisissez un wrapper personnalisé si vous voulez des contrôles sur mesure tout en gardant la main sur tout ; choisissez Video.js ou son composant wrapper si vous avez besoin de HLS, de sous-titres ou de nombreux formats. Trois critères décident : avez-vous besoin d’une interface personnalisée, avez-vous besoin de streaming adaptatif (HLS/DASH) et combien de dépendances pouvez-vous tolérer ?

ApprocheDépendances supplémentairesEffort d’interface personnaliséeHLS / sous-titresÀ choisir quand
<video> natifAucuneVous construisez chaque contrôleHLS natif uniquement (Safari)Clip simple, bundle minimal
Composant wrapper personnaliséAucuneContrôle total via les slotsHLS natif uniquementInterface sur mesure, réutilisée dans toute l’application
Video.js / @videojs-player/vuevideo.js (+ wrapper)Habillage ou surchargeOui, intégréÉtendue des formats, streaming, pistes

<video> HTML5 natif dans Vue (commencez ici)

Le moyen le plus rapide d’ajouter la lecture vidéo dans Vue est un élément <video> natif avec des propriétés liées via :src, poster et preload, plus une template ref() pour appeler l’API HTMLMediaElement : play(), pause() et .muted. Dans Vue 3 <script setup>, liez les événements média natifs comme timeupdate, loadedmetadata et ended directement dans le template, afin que Vue attache et retire les écouteurs à votre place.

<script setup>
import { ref } from 'vue'

const videoRef = ref(null)
const playing = ref(false)
const muted = ref(false)
const current = ref(0)
const duration = ref(0)

function togglePlay() {
  const el = videoRef.value
  el.paused ? el.play() : el.pause()
}

function toggleMute() {
  const el = videoRef.value
  el.muted = !el.muted
  muted.value = el.muted
}
</script>

<template>
  <video
    ref="videoRef"
    src="/media/clip.mp4"
    poster="/media/poster.jpg"
    preload="metadata"
    playsinline
    @play="playing = true"
    @pause="playing = false"
    @ended="playing = false"
    @loadedmetadata="duration = $event.target.duration"
    @timeupdate="current = $event.target.currentTime"
  />
  <div>
    <button @click="togglePlay">{{ playing ? 'Pause' : 'Play' }}</button>
    <button @click="toggleMute">{{ muted ? 'Unmute' : 'Mute' }}</button>
    <span>{{ current.toFixed(0) }}s / {{ duration.toFixed(0) }}s</span>
  </div>
</template>

La template ref="videoRef" se résout en l’élément du DOM accessible via videoRef.value. Accédez-y dans les gestionnaires d’événements ou dans onMounted, jamais avant que le composant ne soit monté. Avec l’Options API, les équivalents sont this.$refs.videoRef et le hook mounted. Si vous attachez des écouteurs manuellement avec addEventListener, retirez-les dans onUnmounted ; passer par @event dans le template évite entièrement cette catégorie de fuite.

Composant de lecteur personnalisé réutilisable

Pour réutiliser la logique du lecteur dans toute une application, encapsulez le <video> natif dans un composant qui expose ses contrôles et son état via un scoped slot, afin que chaque usage compose ses propres boutons et sa propre barre de progression sans dupliquer le câblage de la lecture.

<!-- VideoPlayer.vue -->
<script setup>
import { ref } from 'vue'
defineProps({ src: String, poster: String })
const emit = defineEmits(['timeupdate', 'ended'])

const videoRef = ref(null)
const playing = ref(false)

function togglePlay() {
  const el = videoRef.value
  el.paused ? el.play() : el.pause()
}
</script>

<template>
  <video
    ref="videoRef"
    :src="src"
    :poster="poster"
    playsinline
    @play="playing = true"
    @pause="playing = false"
    @timeupdate="emit('timeupdate', $event.target.currentTime)"
    @ended="emit('ended')"
  />
  <slot name="controls" :playing="playing" :toggle-play="togglePlay" />
</template>

Les consommateurs récupèrent playing et togglePlay dans les props du slot et affichent l’interface dont ils ont besoin. Un seul lecteur de base peut alimenter aussi bien une intégration minimale limitée à la lecture qu’un lecteur complet avec barre de progression, tout en gardant la logique média centralisée en un seul endroit.

<VideoPlayer src="/media/clip.mp4" @ended="onEnded">
  <template #controls="{ playing, togglePlay }">
    <button @click="togglePlay">{{ playing ? 'Pause' : 'Play' }}</button>
  </template>
</VideoPlayer>

Quand faut-il utiliser Video.js ?

Utilisez Video.js lorsque vous avez besoin de HLS/streaming adaptatif, de sous-titres et de pistes textuelles, d’un habillage cohérent, ou d’une étendue de formats supérieure à ce que garantit le <video> natif. Installez video.js, affichez un <video class="video-js">, initialisez videojs(ref, options) dans onMounted, importez la feuille de style et détruisez le lecteur au démontage.

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import videojs from 'video.js'
import 'video.js/dist/video-js.css' // required, or the player renders unstyled

const videoRef = ref(null)
let player = null

const options = {
  autoplay: false,
  controls: true,
  preload: 'auto',
  fluid: true,
  sources: [{ src: '/media/clip.mp4', type: 'video/mp4' }]
}

onMounted(() => {
  player = videojs(videoRef.value, options)
})

onBeforeUnmount(() => {
  if (player) player.dispose()
})
</script>

<template>
  <video ref="videoRef" class="video-js" playsinline />
</template>

Deux erreurs sont faciles à commettre ici : le nom de la template ref doit correspondre à celui que vous lisez dans onMounted (une paire mal appariée videoJsPlayer/videoPlayer déclenche une erreur), et dispose() doit être appelé dans onBeforeUnmount pour Vue 3. beforeDestroy est un hook Vue 2, et Vue 2 a atteint sa fin de vie le 31 décembre 2023. La ligne stable actuelle est Video.js 8.x, avec la version 8.24.0 publiée en août 2026. Une version modulaire, Video.js 10, est en bêta et n’est pas encore disponible en version générale : la chronologie du dépôt v10 indique toujours que la disponibilité générale est en cours de travaux, avec une parité entre le cœur de Video.js et les modules contrib visée pour fin 2026. Restez sur la 8.x en production et n’épinglez pas la version lors de l’installation : npm install video.js.

Composant prêt à l’emploi : @videojs-player/vue

Le chemin le plus court vers Video.js dans Vue 3 est @videojs-player/vue, un composant <video-player> clé en main avec des props réactives (src, sources, poster, controls, loop, volume, fluid, playsinline, tracks) et un scoped slot { player, state } pour les contrôles personnalisés. Il gère l’initialisation et le nettoyage en interne, si bien qu’un clip HLS se résume à un simple changement de source sur une ligne.

<script setup>
import { VideoPlayer } from '@videojs-player/vue'
import 'video.js/dist/video-js.css'
</script>

<template>
  <video-player
    src="https://example.com/stream/playlist.m3u8"
    poster="/media/poster.jpg"
    controls
    fluid
    playsinline
    :volume="0.6"
    @ready="(payload) => console.log(payload.state)"
  >
    <template #default="{ player, state }">
      <button @click="state.playing ? player.pause() : player.play()">
        {{ state.playing ? 'Pause' : 'Play' }}
      </button>
    </template>
  </video-player>
</template>

Une réserve mérite d’être connue avant de l’adopter : c’est le wrapper Vue 3 standard, mais sa publication sur npm est bloquée à la v1.0.0, publiée en 2022, et les scanners de dépendances le signalent comme peu maintenu. Sa plage de peer-dependency publiée réclame toujours video.js 7.x, si bien que l’associer à Video.js 8 génère un avertissement de peer-dependency lors de l’installation. Si vous êtes sur Vue 2, utilisez le build historique vue-video-player référencé depuis la section legacy du dépôt. Les versions actuelles de @videojs-player/vue ciblent uniquement Vue 3.

Checklist des pièges spécifiques à Vue

La plupart des bugs de type « la vidéo ne se lit pas » dans Vue proviennent d’une poignée de règles de plateforme qui passent la revue de code mais échouent sur les appareils réels. Les défaillances liées à la lecture automatique et à playsinline en particulier restent invisibles jusqu’à ce qu’un utilisateur les rencontre — précisément le type de problème spécifique à un appareil que le session replay met en évidence à partir de sessions réelles.

  • Nettoyez au démontage. Appelez player.dispose() pour Video.js et retirez tout gestionnaire addEventListener ajouté manuellement dans onUnmounted, sinon chaque cycle montage/démontage provoque une fuite.
  • Importez le CSS. import 'video.js/dist/video-js.css', faute de quoi le lecteur reste sans style.
  • La lecture automatique en sourdine est obligatoire. Les navigateurs bloquent la lecture automatique avec le son ; définissez à la fois muted et autoplay, conformément à la politique de lecture automatique de Chrome.
  • playsinline pour iOS. Sans l’attribut playsinline, iOS Safari sur iPhone ouvrira généralement la vidéo en plein écran ; l’iPad se comporte différemment.
  • Utilisez les template refs, pas les requêtes DOM. Accédez à l’élément via ref(), jamais via document.querySelector.

Commencez en natif : un <video> avec liaisons met en place la lecture en quelques minutes, sans aucune dépendance. Passez à Video.js ou @videojs-player/vue dès que vous avez besoin de HLS, de sous-titres ou d’une interface cohérente entre navigateurs, et intégrez le nettoyage par dispose() dès le premier commit pour qu’il ne devienne jamais une fuite que vous devrez traquer plus tard.

FAQ

Comment lire un flux HLS (.m3u8) dans une application Vue ?

La vidéo HTML5 native ne lit HLS que dans Safari ; pour du HLS multi-navigateurs, utilisez donc Video.js ou son wrapper @videojs-player/vue, qui embarque la prise en charge de HLS via le moteur videojs-http-streaming. Avec @videojs-player/vue, vous définissez src sur l'URL de votre playlist .m3u8 et le composant gère le moteur de streaming en interne. Dans Chrome ou Firefox sans extension, la vidéo native n'intègre pas HLS, ce qui constitue la principale raison de se tourner vers Video.js.

Pourquoi la lecture automatique ne fonctionne-t-elle pas dans mon lecteur vidéo Vue ?

La lecture automatique en sourdine est généralement autorisée, mais la lecture automatique avec le son exige que l'utilisateur ait d'abord interagi avec le site ; Chrome l'autorise également lorsque le site présente un score Media Engagement Index élevé. Safari applique sa propre politique, similaire. Pour une lecture automatique fiable, vous devez définir à la fois muted et autoplay sur l'élément ou dans les options de Video.js. Cette défaillance est invisible en revue de code car elle dépend de la politique du navigateur et de l'appareil, et non de votre balisage : elle n'apparaît donc que lorsqu'un utilisateur réel charge la page.

Quelle est la différence entre @videojs-player/vue et l'utilisation directe de Video.js ?

@videojs-player/vue est un composant Vue 3 clé en main qui encapsule Video.js : il gère l'initialisation et le nettoyage en interne et expose des props réactives ainsi qu'un scoped slot player et state, alors qu'utiliser Video.js directement signifie afficher un élément video, appeler videojs() dans onMounted et le détruire vous-même dans onBeforeUnmount. Le wrapper demande moins de code, mais sa publication npm est bloquée à la v1.0.0 de 2022 ; Video.js en direct vous donne donc plus de contrôle sur les versions et le cycle de vie.

Puis-je encore utiliser @videojs-player/vue avec Vue 2 ?

Non. Les versions actuelles de @videojs-player/vue ciblent uniquement Vue 3. Le paquet a pris son nom actuel lors de l'ajout de la prise en charge de React, et ce changement constituait une rupture de compatibilité pour les utilisateurs de Vue. Pour Vue 2, vous devez utiliser l'ancien build vue-video-player 5.x, que le dépôt référence toujours dans sa section legacy. Vue 2 a lui-même atteint sa fin de vie le 31 décembre 2023 : tout nouveau développement devrait donc cibler Vue 3.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.