
Vue 3 中优雅地集成 Video.js 播放器从组件封装到功能定制在现代 Web 开发中视频播放是一个常见需求。Video.js 是一个强大且成熟的 HTML5 视频播放器库它提供了丰富的 API 和可定制的 UI。当与 Vue 3 的组合式 API 结合时我们可以轻松地封装一个可复用的视频播放器组件并精细控制其行为如禁用进度条拖动、隐藏不需要的控件等。本文将通过一个完整的示例展示如何在 Vue 3 项目中封装 Video.js 播放器并在父组件中灵活配置。下载依赖npm install video.js一、VideoPlayer 组件实现1. 组件模板首先我们需要在模板中放置一个video标签并为其添加ref属性以便在 JavaScript 中获取 DOM 元素。Video.js 会基于这个元素初始化播放器。template div classvideo-player-container video refvideoRef classvideo-js vjs-default-skin vjs-big-play-centered controls preloadauto :posterposter source :srcsrc :typetype / p classvjs-no-js To view this video please enable JavaScript, and consider upgrading to a web browser that a hrefhttps://videojs.com/html5-video-support/ target_blank supports HTML5 video /a /p /video /div /templaterefvideoRef用于在setup中获取该 DOM 元素。class中添加了 Video.js 需要的默认类名确保样式正常。controls属性启用原生控件但 Video.js 会接管并渲染自己的控件。:poster动态绑定海报图。source标签指定视频源同样使用动态属性。2. 脚本部分组合式 API接下来是组件的核心逻辑。我们将使用 Vue 3 的script setup语法并引入 Video.js 及其样式。script langts setup import { ref, onMounted, onBeforeUnmount } from vue; import videojs from video.js; import video.js/dist/video-js.css; defineOptions({ name: VideoPlayer, inheritAttrs: false }); const props defineProps({ src: { type: String, required: true }, type: { type: String, default: video/mp4 }, poster: { type: String, default: }, options: { type: Object, default: () ({}) }, }); const videoRef ref(null); let player null; const initPlayer () { if (!videoRef.value) return; // 默认配置 const defaultOptions { controls: true, autoplay: false, preload: auto, fluid: true, // 自适应容器宽度 aspectRatio: 16:9, // 宽高比 playbackRates: [0.5, 1, 1.5, 2], // 倍速选项 sources: [{ src: props.src, type: props.type }], poster: props.poster, }; // 合并用户传入的 options const finalOptions { ...defaultOptions, ...props.options }; player videojs(videoRef.value, finalOptions, function onPlayerReady() { console.log(Video.js player ready, this); // 调用进度条控件的 disable 方法禁用拖动和点击 this.controlBar.progressControl.disable(); }); }; const disposePlayer () { if (player) { player.dispose(); player null; } }; // 暴露播放器实例给父组件可选 defineExpose({ player }); onMounted(() { initPlayer(); }); onBeforeUnmount(() { disposePlayer(); }); /script关键点说明默认配置与合并我们定义了一套合理的默认选项如fluid: true使播放器自适应playbackRates提供倍速切换然后通过展开运算符与用户传入的options合并让父组件可以按需覆盖或扩展。进度条禁用在播放器ready回调中我们调用了this.controlBar.progressControl.disable()方法。这是 Video.js 提供的一种禁用进度条交互的方式可以阻止用户拖动或点击进度条跳转。如果你希望保留进度条显示但完全禁止交互这种方法很有效。生命周期管理在onMounted中初始化在onBeforeUnmount中调用dispose()销毁播放器实例避免内存泄漏。暴露实例通过defineExpose将player实例暴露给父组件方便父组件直接调用播放器方法如播放、暂停等。3. 样式简单地为容器添加一些样式限制最大宽度并居中。style scoped .video-player-container { width: 100%; max-width: 800px; margin: 0 auto; } /style二、父组件中使用 VideoPlayer现在我们可以在父组件中引入并使用VideoPlayer并传入自定义配置。template div h1我的视频播放器/h1 VideoPlayer refvideoPlayerRef srchttps://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4 typevideo/mp4 posterhttps://ms.bdimg.com/pacific/0/pic/-782555709_-1732160829.jpg :optionsplayerOptions / /div /template script setup import { ref } from vue; import VideoPlayer from ./components/VideoPlayer.vue; const videoPlayerRef ref(null); const playerOptions { autoplay: false, controls: true, controlBar: { playbackRateMenuButton: false, // 隐藏倍速按钮 seekToLive: false, // 隐藏“跳转至直播”按钮如果有 volumePanel: { inline: false }, // 音量控制样式 }, html5: { vhs: { overrideNative: true }, // HLS 配置 nativeControlsForTouch: false, disablePictureInPicture: true, // 禁用画中画 }, }; // 如果需要调用播放器方法可以通过 videoPlayerRef.value.player 访问 // 例如videoPlayerRef.value.player.play() /script配置解析controlBar选项我们通过playbackRateMenuButton: false隐藏了倍速切换按钮seekToLive: false隐藏直播场景下的“跳转至直播”按钮非直播流无影响volumePanel调整了音量控件的布局。html5选项disablePictureInPicture: true彻底禁用画中画功能确保用户无法通过任何方式进入画中画模式。同时设置了 HLS 相关的vhs配置和nativeControlsForTouch。注意我们并没有在playerOptions中重复定义sources或poster因为这些已经在组件的 props 中传递了。如果需要覆盖也可以在options中传入但要注意合并策略。三、进阶功能与注意事项1. 响应式更新视频源如果父组件的src发生变化我们需要通知播放器更新视频源。可以在VideoPlayer组件中添加一个watch监听props.src并调用player.src()方法更新。watch(()props.src,(newSrc){if(player){player.src({src:newSrc,type:props.type});}});同样地如果需要监听poster变化可以使用player.poster(newPoster)。2. 彻底禁用进度条交互的备选方案虽然progressControl.disable()在很多情况下有效但某些 Video.js 版本可能不支持该方法。更稳健的做法是在ready回调中手动移除进度条的事件监听player.ready(function(){constseekBarthis.controlBar.progressControl.seekBar;seekBar.off(mousedown);seekBar.off(touchstart);seekBar.off(click);});这种方法保留了进度条的视觉显示但阻止了任何鼠标或触摸交互。3. 关于倍速播放我们在默认选项中配置了playbackRates: [0.5, 1, 1.5, 2]但在父组件的options中又通过controlBar.playbackRateMenuButton: false隐藏了倍速按钮。这样做的结果是倍速功能依然存在例如通过键盘快捷键或 API 调用但用户无法通过 UI 操作。如果你希望完全禁止倍速可以不配置playbackRates数组或者监听ratechange事件强制重置速度为 1。4. 移动端兼容性对于 iOS 设备需要注意playsinline属性通常建议在video标签上添加playsinline以防止视频自动全屏。你可以通过options传递该属性constplayerOptions{// ...其他选项html5:{playsinline:true,// ...}};5. 内存泄漏防范务必在组件卸载时调用player.dispose()否则播放器实例会一直占用内存且可能导致事件监听无法释放。四、总结通过以上封装我们获得了一个灵活、可复用的 Vue 3 视频播放器组件。它支持通过 props 传入视频源、海报和自定义配置。合并默认选项和用户选项满足不同场景需求。在播放器初始化后禁用进度条交互防止用户快进。通过controlBar配置隐藏不需要的控件如倍速、画中画按钮。正确管理生命周期避免内存泄漏。父组件可以轻松地使用该组件并传递定制化的options来控制播放器的行为和外观。如果你需要进一步扩展如添加自定义按钮、监听播放事件等Video.js 丰富的事件系统和插件机制也能很好地满足需求。