在 VitePress 中优雅集成基于 CDN 动态加载的 HLS 视频播放器组件

前言

随着网络视频内容的迅猛增长,视频播放已成为前端开发中不可或缺的功能。HTML5 的 <video> 标签为视频播放提供了原生支持,但其默认无法直接播放 HLS(HTTP Live Streaming)格式的 .m3u8 文件。这在需要高质量、跨设备兼容的视频流场景中显得局限。为了解决这一问题,我们可以引入 HLS.js 库,并结合 Vue.js 框架封装一个通用的视频播放组件,不仅实现对 .m3u8 格式的兼容,还能集成懒加载、错误处理和性能优化等功能,从而提升用户体验和页面加载效率。本文将详细介绍如何基于 Vue 封装一个支持 HLS 的视频播放组件,并探讨懒加载等优化手段的实现方式及其实际应用价值。


组件设计目标

  • 灵活的参数支持:通过 Markdown 传入播放地址 src、封面图 poster、自动播放 autoplay、静音 muted 和循环播放 loop 等参数。
  • 动态加载 HLS.js:利用 CDN 按需加载 HLS.js,避免打包时增加项目体积。
  • 按需加载:仅在包含视频播放组件的页面加载 HLS.js。
  • 懒加载优化:借助 IntersectionObserver,实现视口懒加载,仅在视频进入用户视野附近时初始化播放器并加载 HLS.js。
  • 资源复用:多个播放器组件共享同一份 CDN 脚本,避免重复请求。

组件实现:HlsPlayer.vue

将以下代码保存至 .vitepress/theme/components/HlsPlayer.vue

vue
<template>
  <div ref="container">
    <video 
      ref="video" 
      :poster="poster" 
      controls 
      style="width: 100%; max-width: 800px; border-radius: 8px;"
      :autoplay="autoplay"
      :muted="muted"
      :loop="loop"
    ></video>
  </div>
</template>

<script setup>

// 定义组件属性
const props = defineProps({
  src: { type: String, required: true },       // HLS 播放地址
  poster: { type: String, default: '' },       // 视频封面
  autoplay: { type: Boolean, default: false }, // 是否自动播放
  muted: { type: Boolean, default: false },    // 是否静音
  loop: { type: Boolean, default: false }      // 是否循环播放
})

const container = ref(null)
const video = ref(null)
let observer = null

// 全局缓存 HLS.js 加载 Promise,避免重复加载
let hlsJsLoader = null

function loadHlsJsOnce() {
  if (window.Hls) return Promise.resolve(window.Hls)
  if (hlsJsLoader) return hlsJsLoader

  hlsJsLoader = new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.src = 'https://cdn.jsdmirror.com/npm/hls.js@latest'
    script.onload = () => resolve(window.Hls)
    script.onerror = reject
    document.head.appendChild(script)
  })

  return hlsJsLoader
}

async function initPlayer() {
  if (!video.value) return

  // 设置视频元素属性
  video.value.muted = props.muted
  video.value.loop = props.loop

  // Safari 原生支持 HLS
  if (video.value.canPlayType('application/vnd.apple.mpegurl')) {
    video.value.src = props.src
  } else {
    // 动态加载 HLS.js,仅加载一次
    const Hls = await loadHlsJsOnce()
    if (Hls.isSupported()) {
      const hls = new Hls()
      hls.loadSource(props.src)
      hls.attachMedia(video.value)
    } else {
      console.warn('当前浏览器不支持 HLS.js 播放')
    }
  }

  // 尝试自动播放
  if (props.autoplay) {
    video.value.play().catch(() => {
      console.log('⚠️ 自动播放被浏览器阻止,需要用户交互')
    })
  }
}

onMounted(() => {
  if (!('IntersectionObserver' in window)) {
    initPlayer() // 不支持 IntersectionObserver 时直接初始化
    return
  }
  observer = new IntersectionObserver((entries) => {
    for (const entry of entries) {
      if (entry.isIntersecting) {
        initPlayer()
        observer.disconnect()
        break
      }
    }
  }, { rootMargin: '100px' })
  if (container.value) observer.observe(container.value)
})

onBeforeUnmount(() => {
  if (observer) observer.disconnect()
})
</script>

Markdown 中的使用示例

VitePress 会自动注册 .vitepress/theme/components 目录下的组件,您可以在 Markdown 中直接调用:

md
# HLS 视频播放示例

默认播放(需手动触发

<HlsPlayer src="https://raw.chiyu.it/pic/end/video/1.m3u8" />

带封面

<HlsPlayer 
  src="https://raw.chiyu.it/pic/end/video/1.m3u8" 
  poster="https://example.com/cover.jpg" 
/>

静音播放

<HlsPlayer src="https://raw.chiyu.it/pic/end/video/1.m3u8" autoplay muted />

静音自动播放且循环:

<HlsPlayer src="https://raw.chiyu.it/pic/end/video/1.m3u8" autoplay muted loop />

关键点解析

  • 懒加载机制:通过 IntersectionObserver,仅在视频进入视口附近时初始化播放器,避免页面初次加载时占用过多资源,从而提升首屏加载速度。
  • CDN 动态加载 HLS.js:首次播放时通过 <script> 标签加载 HLS.js,并利用 Promise 缓存确保全局只加载一次,减少资源浪费。
  • 参数灵活性:支持播放地址、封面图、自动播放、静音和循环播放等参数,满足多种使用场景。
  • Safari 原生支持优先:检测浏览器是否原生支持 .m3u8,在 Safari 中跳过 HLS.js 加载以优化性能。

总结

通过上述方案,您可以在 VitePress 中轻松集成支持 HLS 格式的视频播放功能。该组件不仅保证了播放兼容性,还通过懒加载和动态加载显著提升了页面性能和加载速度。其灵活的参数配置和资源按需加载设计,使其成为在静态文档系统中嵌入直播或点播视频的理想选择。

示例:

赞赏博主
评论 隐私政策