
在內容平台上面常常會有製作影片播放器的需求,我自己工作上本來都是使用其他的影片播放器套件來擴充與樣式的開發,但是近期因為一些事情偶然知道了 Media Chrome 這款影片播放器,不管是擴充功能的開發又或是操作的體驗都比其他的播放器套件來的順暢及簡單,所以我就花了點時間將專案上的播放器組件全部進行了一次大重構。這邊就稍微整理一下我使用 Media Chrome 後整理出來的一些經驗,寫了一點簡單的入門教學跟大家分享!
Media Chrome 是由 Mux 團隊開發的一套 Web Components 播放器控制元件庫。它的核心理念是「將 UI 與播放引擎分離」,讓你可以用 HTML 標籤組合出高度客製化的影片播放器。

官網:https://www.media-chrome.org/
1.先透過 npm 安裝
npm install media-chrome
2.然後在 import
import 'media-chrome'
3.建立一個基礎的播放器容器
<media-controller>
<video slot="media" src="https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4"></video>
<media-control-bar>
<media-play-button></media-play-button>
<media-mute-button></media-mute-button>
<media-volume-range></media-volume-range>
<media-time-display></media-time-display>
<media-time-range></media-time-range>
<media-duration-display></media-duration-display>
<media-playback-rate-button></media-playback-rate-button>
<media-fullscreen-button></media-fullscreen-button>
</media-control-bar>
</media-controller>
這邊可以看到除了<media-controller> 跟 <video> 以外添加了很多組件,這些就是我們播放器的內部的擴充元件,想要什麼就加入什麼,不需要什麼就直接拿掉就好,最後長這樣!

我們可以看到下方的控制列上有很多的 UI 這些就是對應到我們剛剛的那些 Web Components 的組件!
我把一些常見的 Web Components 的組件給列出來
| 組件 | 說明 |
| <media-controller> | 核心容器,負責協調所有控制元件與媒體元素的溝通 |
| <media-control-bar> | 控制列容器,預設顯示在底部 |
| <media-play-button> | 播放/暫停按鈕 |
| <media-mute-button> | 靜音按鈕 |
| <media-volume-range> | 音量滑桿 |
| <media-time-range> | 時間進度條 |
| <media-time-display> | 時間顯示 |
| <media-fullscreen-button> | 全螢幕按鈕 |
| <media-pip-button> | 子母畫面按鈕 |
| <media-playback-rate-button> | 播放速度切換 |
| <media-captions-button> | 字幕開關 |
| <media-seek-forward-button> | 快轉按鈕 |
| <media-seek-backward-button> | 倒轉按鈕 |
關於這些組件 Media Chrome 都有提供相對的 slots 用來告訴 <media-controller> 內部的組件的一些狀態以及調整媒體控制列的位置,像是一開始的時候的 <video> 身上就有去指定 media slots。
<video slot="media"></video>
將組件定位到頂部
<media-control-bar slot="top-chrome">
<!-- 其他組件 -->
</media-control-bar>

將組件置中
<media-control-bar slot="centered-chrome">
<!-- 其他組件 -->
</media-control-bar>

將組件置底部 (因為預設就是底部,所以不用給)
<media-control-bar>
<!-- 其他組件 -->
</media-control-bar>

關於更多的細節可以參考文件:https://www.media-chrome.org/docs/en/position-controls
我們可以使用 slot 來替換預設的 icon,來看看以下範例
<media-control-bar>
<!-- 預設 -->
<media-play-button></media-play-button>
<!-- 客製化 icon -->
<media-play-button>
<!-- 播放圖示 -->
<svg slot="play" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" fill="#ffff00"/>
</svg>
<!-- 暫停圖示 -->
<svg slot="pause" viewBox="0 0 24 24">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" fill="#ffff00"/>
</svg>
</media-play-button>
</media-control-bar>
我們在 <media-play-button> 裡面塞入了兩個 svg icon,然後添加了 slot,分別指定 play 與 pause,這兩個狀態就分別代表了 <media-play-button> 的播放跟暫停狀態,他就會去替換原本預設的 icon 圖示,所以看到預覽圖上面的黃色 icon 就是我替換的 buttom icon 。
再舉一個例子,關於聲音大到小的 icon 狀態,其實也可以改

<media-control-bar>
<!-- 當前聲音高到低的 icon -->
<media-mute-button>
<h1 slot="high">高音量</h1>
<h1 slot="medium">中音量</h1>
<h1 slot="low">低音量</h1>
<h1 slot="off">靜音</h1>
</media-mute-button>
<!-- 聲音大小拖曳 -->
<media-volume-range></media-volume-range>
</media-control-bar>
</media-controller>
還可以搭配 CSS 來做一些樣式的調整
media-mute-button {
border-radius: 50%;
height: 70px;
width: 70px;
background-color: red;
}
media-volume-range {
background-color: transparent;
}
<media-controller>
<video slot="media" src="https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4"></video>
<media-control-bar>
<!-- 當前聲音高到低的 icon -->
<media-mute-button>
<h1 slot="high">高</h1>
<h1 slot="medium">中</h1>
<h1 slot="low">低</h1>
<h1 slot="off">無</h1>
</media-mute-button>
<!-- 聲音大小拖曳 -->
<media-volume-range></media-volume-range>
</media-control-bar>
</media-controller>

客製化 UI 就是這麼簡單!
詳細的 Slots 都可以在官網的文件裡面看到
<media-play-button> : https://www.media-chrome.org/docs/en/components/media-play-button
<media-mute-button> : https://www.media-chrome.org/docs/en/components/media-mute-button
Media Chrome 的事件系統分為兩類:原生媒體事件 和 Media Chrome 自訂事件.本次教學只會先針對原生媒體事件來做介紹, Media Chrome 自訂事件我們下次再來細講。
以下這些原生媒體事件可以直接在 <video> 上監聽:
| 事件名稱 | 觸發時機 |
| play | 開始播放(包含從暫停恢復) |
| pause | 暫停播放 |
| playing | 實際開始播放(緩衝完成後) |
| ended | 播放結束 |
| waiting | 等待資料緩衝中 |
| stalled | 瀏覽器嘗試取得資料但無法取得 |
| suspend | 瀏覽器暫停取得資料 |
| abort | 資源載入被中止 |
| emptied | 媒體元素被清空 |
| 事件名稱 | 觸發時機 |
| timeupdate | 播放時間更新(約每 250ms) |
| durationchange | 影片總長度變更 |
| seeking | 開始跳轉(拖動進度條) |
| seeked | 跳轉完成 |
| progress | 下載進度更新 |
| 事件名稱 | 觸發時機 |
| loadstart | 開始載入資源 |
| loadedmetadata | metadata 載入完成(初始化 UI、取得影片資訊) |
| loadeddata | 第一幀資料載入完成 |
| canplay | 可以開始播放 |
| canplaythrough | 可順暢播放到結束 |
| 事件名稱 | 觸發時機 |
| volumechange | 音量或靜音狀態變更 |
| ratechange | 播放速度變更 |
| error | 載入或播放錯誤 |
| resize | 影片尺寸變更 |
const video = document.querySelector('video')
// 播放相關
video.addEventListener('play', () => console.log('開始播放'))
video.addEventListener('pause', () => console.log('已暫停'))
video.addEventListener('playing', () => console.log('正在播放中'))
video.addEventListener('ended', () => console.log('播放結束'))
video.addEventListener('waiting', () => console.log('等待緩衝中'))
// 時間相關
video.addEventListener('timeupdate', (e) => {
console.log('當前時間:', e.target.currentTime)
})
video.addEventListener('durationchange', (e) => {
console.log('影片長度:', e.target.duration)
})
video.addEventListener('seeking', () => console.log('正在跳轉'))
video.addEventListener('seeked', () => console.log('跳轉完成'))
// 載入相關
video.addEventListener('loadstart', () => console.log('開始載入'))
video.addEventListener('loadedmetadata', () => console.log('metadata 已載入'))
video.addEventListener('loadeddata', () => console.log('資料已載入'))
video.addEventListener('canplay', () => console.log('可以播放'))
video.addEventListener('canplaythrough', () => console.log('可以順暢播放'))
video.addEventListener('progress', () => console.log('下載進度更新'))
// 音量相關
video.addEventListener('volumechange', (e) => {
console.log('音量:', e.target.volume, '靜音:', e.target.muted)
})
// 錯誤處理
video.addEventListener('error', (e) => {
console.error('錯誤:', e.target.error)
})
// 播放速率
video.addEventListener('ratechange', (e) => {
console.log('播放速度:', e.target.playbackRate)
})
只要有了這些事件基本上在客製化播放器 UI 與網頁之間的互動我想應該會變的很簡單!
Media Chrome 的設計有別於其他播放器套件,是真的將 UI 給分開,自己實際用過之後覺得客製化播放器功能整個簡單了起來,推薦給讀者們一個新的選擇。不知道我這樣介紹後大家有沒有對 Media Chrome 這個播放器套件有了初步的認識呢~
後面的教學再來慢慢介紹 Media Chrome 的其他功能,敬請期待!