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.
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,controlsetposterne nécessite aucune bibliothèque. - Dans Vue 3 avec
<script setup>, récupérez l’élément via une templateref()et appelez l’API média native survideoRef.valueà l’intérieur deonMounted, jamais viadocument.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()dansonBeforeUnmount(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
mutedetautoplay, et ajouterplaysinlinepour 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 ?
| Approche | Dépendances supplémentaires | Effort d’interface personnalisée | HLS / sous-titres | À choisir quand |
|---|---|---|---|---|
<video> natif | Aucune | Vous construisez chaque contrôle | HLS natif uniquement (Safari) | Clip simple, bundle minimal |
| Composant wrapper personnalisé | Aucune | Contrôle total via les slots | HLS natif uniquement | Interface sur mesure, réutilisée dans toute l’application |
Video.js / @videojs-player/vue | video.js (+ wrapper) | Habillage ou surcharge | Oui, intégré | Étendue des formats, streaming, pistes |
Discover how at OpenReplay.com.
<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 gestionnaireaddEventListenerajouté manuellement dansonUnmounted, 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
mutedetautoplay, conformément à la politique de lecture automatique de Chrome. playsinlinepour iOS. Sans l’attributplaysinline, 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 viadocument.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.
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