Admin 元件
Video Player
影片播放器(vidstack)。來源:MP4、HLS、YouTube;控制:快進快退、解析度、播放速度、音量、全螢幕。
安裝
Terminal
pnpm dlx shadcn-vue add @admin/video-playerimport { AdminVideoPlayer, AdminVideoPlayerControls, AdminVideoPlayerFullscreen, AdminVideoPlayerPlay, AdminVideoPlayerProgress, AdminVideoPlayerSettings, AdminVideoPlayerTime, AdminVideoPlayerToolbar, AdminVideoPlayerVolume} from '@/components/admin/video-player'vidstack 是一組 web components,需要在專案 build 設定告訴 Vue compiler 把 media-* 開頭的 tag 當成 native custom element:
Nuxt 3 / 4
nuxt.config.ts
export default defineNuxtConfig({ vue: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('media-') } }})Vue 3 + Vite
vite.config.ts
import vue from '@vitejs/plugin-vue'import { defineConfig } from 'vite'export default defineConfig({ plugins: [ vue({ template: { compilerOptions: { isCustomElement: (tag) => tag.startsWith('media-') } } }) ]})用法
傳入 src 即可播放,元件根據 src 字串自動辨識 provider:YouTube URL → YouTube provider、.m3u8 → HLS、其他 → native MP4 / WebM
<script setup lang="ts">import { AdminVideoPlayer } from '@/components/admin/video-player'</script><template> <admin-video-player poster="https://files.vidstack.io/sprite-fight/poster.webp" src="https://files.vidstack.io/sprite-fight/720p.mp4" /></template>場景
HLS 串流(含解析度切換)
來源為 .m3u8 時,齒輪設定菜單會出現「解析度」區塊,列出 vidstack qualities 過濾後的 480 / 720 / 1080 選項;切換後寫入 localStorage key admin:player:resolution,下次播放新 HLS 影片自動套用同設定。
<script setup lang="ts">import { AdminVideoPlayer } from '@/components/admin/video-player'</script><template> <admin-video-player poster="https://files.vidstack.io/sprite-fight/poster.webp" src="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8" /></template>YouTube
src 為 YouTube URL(youtube.com/... / youtu.be/...)或 youtube/<id> 時自動切換到 YouTube provider;齒輪菜單不顯示解析度區塊(YouTube provider 不支援切換)。
<script setup lang="ts">import { ref } from 'vue'import { cn } from '@/lib/utils'import { AdminVideoPlayer } from '@/components/admin/video-player'const presets = [ 'https://www.youtube.com/watch?v=_cMxraX_5RE', 'https://www.youtube-nocookie.com/watch?v=_cMxraX_5RE', 'https://www.youtube.com/embed/_cMxraX_5RE', 'https://youtu.be/_cMxraX_5RE', 'youtube/_cMxraX_5RE'] as constconst src = ref<string>(presets[0])const draft = ref<string>(presets[0])function applyDraft() { const trimmed = draft.value.trim() if (trimmed) { src.value = trimmed }}</script><template> <div class="flex w-full flex-col gap-3"> <form class="flex gap-2" @submit.prevent="applyDraft"> <input v-model="draft" placeholder="貼上 YouTube URL…" type="text" :class=" cn(` flex-1 rounded-md border border-bg-60 bg-bg-90 px-3 py-1.5 text-content-medium text-text-90 outline-none focus:border-primary-50 `) " /> <button type="submit" :class=" cn(` rounded-md bg-primary-50 px-3 py-1.5 text-content-medium text-white hover:bg-primary-60 `) " > 套用 </button> </form> <div class="flex flex-wrap gap-2"> <button v-for="preset in presets" :key="preset" type="button" :class=" cn(` rounded-md border border-bg-60 bg-bg-90 px-2 py-1 text-caption-medium text-text-70 transition-colors hover:bg-bg-70 `) " @click=" () => { draft = preset applyDraft() } " > {{ preset }} </button> </div> <admin-video-player :key="src" :src="src" /> </div></template>API 參考
組成
<template> <admin-video-player :poster :src> <admin-video-player-toolbar> <admin-video-player-play /> <admin-video-player-time /> <admin-video-player-controls /> <admin-video-player-progress /> <admin-video-player-settings /> <admin-video-player-volume /> <admin-video-player-fullscreen /> </admin-video-player-toolbar> </admin-video-player></template>admin-video-player
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
src* | MediaSrc | — | 影片來源(vidstack `MediaSrc` 格式) |
poster | string | undefined | — | 載入前顯示之封面圖 URL |
class | ClassValue | — | 根元素之自訂 class |
* 代表必填
Events
| 名稱 | Payload | 說明 |
|---|---|---|
ended | — | 播放結束時觸發 |
error | Error | 載入或播放發生錯誤時觸發 |
pause | — | 暫停播放時觸發 |
play | — | 開始播放時觸發 |
timeUpdate | number | 播放進度更新時觸發,payload 為當前秒數 |
fullscreenChange | boolean | 全螢幕狀態變更時觸發 |
qualityChange | number | 解析度變更時觸發,payload 為當前 height |
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
default | {} | — |
admin-video-player-controls
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
admin-video-player-fullscreen
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
admin-video-player-play
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
admin-video-player-progress
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
admin-video-player-settings
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
admin-video-player-time
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
admin-video-player-toolbar
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
Slots
| 名稱 | Bindings | 說明 |
|---|---|---|
default | {} | — |
admin-video-player-volume
Props
| 名稱 | 型別 | 預設值 | 說明 |
|---|---|---|---|
class | ClassValue | — | 根元素之自訂 class |
注意事項
- 必須加
isCustomElement設定:未加上時 dev console 會對<media-*>元素噴 warning,詳細寫法見「安裝」章節。 - 不支援 SSR:vidstack 為 browser-only;元件殼不含
<ClientOnly>。Nuxt 請自行以<ClientOnly>包覆;純 CSR 不需處理。見 安裝 · SSR。 - YouTube 解析度不可切:vidstack YouTube provider 不暴露 quality API,齒輪菜單會自動隱藏解析度區塊。
- MP4 解析度不可切:單一 MP4 來源沒有 quality 變體,齒輪菜單也不會顯示解析度區塊;如需多解析度切換,請改用 HLS 串流。
- HLS qualities 載入時序:
.m3u8manifest 下載前qualities為空陣列,UI 顯示「載入中…」;manifest 解析後自動填入並依localStoragekeyadmin:player:resolution套用最接近且 ≤ 目標的 quality。 - 音量、解析度跨實例共享:所有 player 實例(含 audio-player)共用
admin:player:*namespace;多 tab 不互相同步避免操作被覆蓋。 - 全螢幕請求失敗:若 iframe 沒給
allow="fullscreen"或瀏覽器拒絕,toggleFullscreen不會 throw,會 emiterror事件供消費端處理。