
本文將帶領各位中級前端開發者,一步步建立自己的音訊與影片播放器介面。我們將從基本的 HTML5 <audio>與<video>標籤開始,逐步添加自訂的播放按鈕、音量控制、進度條、全螢幕按鈕等介面元件,並利用 JavaScript 控制播放、暫停、跳轉(快轉/倒退)、音量調整、播放速率設定等功能。過程中也會探討播放列表、自訂圖示、更換媒體來源、以及多語字幕切換等進階應用。每個主要環節都附有清晰的範例程式碼,方便讀者直接複製實作。讓我們開始為媒體播放器注入新的生命力,創造一個專屬於自己網站的影音體驗吧!
建立 HTML5 音訊與影片播放器元素
首先,我們需要在 HTML 中建立音訊和影片播放器的基本結構。HTML5 已經提供了方便的<audio>和<video>標籤,用於嵌入音訊檔案與影片檔案。這兩種標籤的基本用法很相似,都可以包含多個<source>子標籤來提供不同格式的媒體來源,確保跨瀏覽器的播放相容性。例如,影片常見的格式有 MP4(H.264 編碼)、WebM、Ogg 等;音訊則有 MP3、Ogg、WAV 等。透過提供多種格式來源,瀏覽器會自動選擇第一個能播放的格式,提升相容性。
下面的程式碼範例展示了如何使用<video>和<audio>標籤嵌入媒體。我們為影片設定了寬度屬性與海報圖(poster)以在載入影片前顯示靜態預覽,並使用preload="metadata"讓瀏覽器只預先載入媒體的長度等中繼資料(節省頻寬)。兩個標籤都包含 multiple <source> 來源,以及一個文字作為備援資訊(當瀏覽器不支援 HTML5 媒體時會顯示)。預設加上controls屬性以顯示瀏覽器內建的控制介面,確保在使用者停用 JavaScript 時仍有播放控件可用。稍後我們會透過 JavaScript 隱藏這些預設控制並呈現自訂介面。
<!-- HTML: 建立影片播放器 -->
<div class="player-container" id="videoPlayerContainer">
<video id="videoPlayer" width="640" poster="preview.webp" preload="metadata" controls>
<source src="movie.mp4" type="video/mp4" />
<source src="movie.webm" type="video/webm" />
您的瀏覽器不支援 HTML5 影片標籤。
</video>
</div>
<!-- HTML: 建立音訊播放器 -->
<div class="player-container" id="audioPlayerContainer">
<audio id="audioPlayer" preload="metadata" controls>
<source src="song.mp3" type="audio/mpeg" />
<source src="song.ogg" type="audio/ogg" />
您的瀏覽器不支援 HTML5 音訊標籤。
</audio>
</div>
上述結構建立了基本的影片播放器和音訊播放器。此時,如果直接在頁面打開,瀏覽器會替我們呈現它內建的媒體控制列。然而,我們的目標是自訂播放介面,因此接下來要動手添加自己的控制項 HTML 元素,並以 CSS 調整其外觀。請注意,我們將<video>與<audio>各自包裹在一個外層容器<div class="player-container">中,這樣做有助於之後在需要時統一處理播放器的位置排版(例如將自訂控制列固定在影片下方或覆蓋在影片上)。
添加自訂控制項的 HTML 標籤
為了打造自己的播放器介面,我們需要在 HTML 中定義一組自訂控制按鈕和滑桿。可以將這些控制元件放在一個容器中,緊跟在媒體元素之後。下面範例中,我們新增了一個<div class="controls">容器,其中包含播放/暫停按鈕、進度條、音量控制和全螢幕按鈕等元素。每個按鈕使用<button>標籤並設定了對應的id,方便稍後用 JavaScript 綁定事件。進度條和音量條則使用<input type="range">滑桿,使用者可拖曳滑桿調整數值。我們也加入一個靜音按鈕來切換聲音,以及一個播放速率選單讓使用者調整播放速度。初始狀態下,我們給控制容器賦予一個類別hidden(隱藏),稍後透過 CSS 將其隱藏,待 JavaScript 確認載入後再顯示。以下是自訂控制項的 HTML 結構:
<!-- HTML: 自訂控制介面 -->
<div class="controls hidden" id="videoControls">
<!-- 播放/暫停按鈕 -->
<button id="playPauseBtn" type="button" class="control-btn paused">播放</button>
<!-- 進度條滑桿 -->
<input id="progressBar" type="range" value="0" min="0" step="0.1">
<!-- 已播放時間/總時長顯示(可選擇性加入) -->
<span id="timeDisplay">0:00 / 0:00</span>
<!-- 音量控制:靜音按鈕與音量滑桿 -->
<button id="muteBtn" type="button" class="control-btn">靜音</button>
<input id="volumeSlider" type="range" min="0" max="1" step="0.1" value="1">
<!-- 播放速率選單 -->
<select id="speedSelect">
<option value="0.5">0.5x</option>
<option value="1" selected>1x</option>
<option value="1.5">1.5x</option>
<option value="2">2x</option>
</select>
<!-- 全螢幕按鈕 -->
<button id="fullscreenBtn" type="button" class="control-btn">全螢幕</button>
</div>
在上述 HTML 中,我們準備好了自訂的控制介面元素:
- 播放/暫停按鈕:使用 <button> 並給予 id="playPauseBtn"。我們預先給它一個類別paused,代表目前處於暫停狀態(因此按鈕顯示「播放」圖示或文字)。稍後透過 JS 切換這個類別,可在播放和暫停圖示間切換。
- 進度條:使用 <input type="range"> 滑桿呈現播放進度。初始 value 為0,後續會將其最大值(max)設為媒體總長度(秒),並隨播放更新 value 以反映當前進度。使用者也可拖動滑桿跳轉播放位置。
- 時間顯示(非必需):一個 <span id="timeDisplay"> 用於顯示當前播放時間和總時長,例如 "1:23 / 3:45"。這在教學中屬於加分項,稍後我們會提及如何更新它。
- 音量控制:包括一個靜音切換按鈕(id="muteBtn")和一個音量調整滑桿(id="volumeSlider")。滑桿的值範圍設定為0到1對應音量的0%~100%,步進0.1表示每次調整10%音量。初始值為1(100%音量)。
- 播放速率選單:使用 <select id="speedSelect"> 提供幾種常用播放速度選項(0.5x、1x、1.5x、2x)。預設選中正常速度1x。用戶選擇後可以透過 JS 更改影片的播放速率。
- 全螢幕按鈕:一個 <button id="fullscreenBtn"> 來切換全螢幕模式。
請將上述控制項容器放置在對應的播放器容器內,例如放在先前範例的<div id="videoPlayerContainer">中、緊接在<video>之後。對於音訊播放器,如需相似控制,也可建立一組對應的控制容器(或共用相同的結構)。有了這些 HTML 元素,我們便為客製化介面打下了基礎。下一步,我們將運用 CSS 讓這些元素美化版面、融入設計,並隱藏瀏覽器的原生控制界面。
使用 CSS 打造自訂的播放器介面
現在我們已經有了媒體元素和自訂控制項的 HTML 結構,接下來利用 CSS 來設計這些控制介面的外觀。目標是讓自訂控制列整齊地排列,樣式符合我們網站的風格,同時在適當時機隱藏瀏覽器預設的控制列。
版面配置與預設控制項隱藏
首先,為了讓自訂控制列正常顯示,我們需要隱藏原生控制介面。雖然在 HTML 我們有加上controls屬性做為無 JavaScript 時的後援,但在載入頁面並確認 JavaScript 可用後,我們會將video.controls和audio.controls屬性設為false(關閉原生控制)。在 CSS 方面,我們已經給自訂控制容器設定了一個hidden類別,預設使用 CSS 將其隱藏,避免與原生控制重疊。當 JS 啟動時,我們再動態移除hidden類別以顯示自訂控制列。以下是基本的 CSS 設定:
/* 隱藏自訂控制列 (初始狀態) */
.controls.hidden {
display: none;
}
/* 控制列容器的排版 */
.player-container {
max-width: 640px; /* 父容器寬度,可依需要調整或以百分比呈現響應式 */
margin: 1em auto;
/* 可選擇性地 position: relative; 以便進一步定位內部元素(如將控制列覆蓋在影片上) */
}
.controls {
display: flex;
align-items: center;
justify-content: flex-start;
gap: 10px; /* 控制項間距 */
padding: 8px 12px; /* 控制列內距,讓按鈕不貼邊 */
background: #333; /* 控制列背景色,例如半透明黑色: rgba(0,0,0,0.5) */
color: #fff; /* 文字與圖示顏色為白色,便於在深色背景上顯示 */
}
上述 CSS 先將controls.hidden設為display: none隱藏,並設定.controls容器為彈性盒模型(flexbox),使裡面的按鈕和滑桿能水平排列。我們加上一些gap來分隔各控制項,並使用padding增添內距。控制列背景設為深色、文字圖示為淺色,以確保可讀性。您可以依網站主題調整這些色彩。父容器.player-container我們限制了最大寬度並置中(auto margin),以在頁面上呈現良好的佈局。如果希望控制列覆蓋在影片畫面上,可以將.player-container設為position: relative,然後將.controls容器用position: absolute; bottom: 0等方式定位在容器底部。但這裡我們示範的是簡單地將控制列置於影片下方。
按鈕樣式與自訂圖示
接下來,針對各個按鈕,我們將移除瀏覽器預設樣式並套用自訂圖示。為了外觀一致,我們可先為所有控制按鈕設定一些共用樣式,例如固定尺寸、移除邊框背景,以及使用游標提示可點擊。然後針對特定按鈕狀態套用背景圖示。以下範例將播放/暫停按鈕與靜音按鈕的圖示自訂:
/* 共用按鈕外觀重置與調整 */
.control-btn {
width: 32px;
height: 32px;
background: none;
border: none;
cursor: pointer;
outline: none; /* 移除點擊時的輪廓 */
/* 隱藏按鈕文字,用圖示呈現 */
color: transparent;
text-shadow: none;
}
/* 滑鼠懸停或聚焦時微微改變透明度,給予回饋 */
.control-btn:hover, .control-btn:focus {
opacity: 0.8;
}
/* 播放/暫停按鈕的圖示:根據狀態切換 */
#playPauseBtn {
background: center center no-repeat;
background-size: contain;
}
#playPauseBtn.paused {
/* 暫停狀態時顯示播放圖示 */
background-image: url("icon-play.webp");
}
#playPauseBtn:not(.paused) {
/* 播放中狀態時顯示暫停圖示 */
background-image: url("icon-pause.webp");
}
/* 靜音按鈕的圖示切換 */
#muteBtn {
width: 28px;
height: 28px;
background: center center no-repeat;
background-size: contain;
}
#muteBtn.muted {
background-image: url("icon-muted.webp"); /* 靜音狀態圖示 */
}
#muteBtn:not(.muted) {
background-image: url("icon-volume.webp"); /* 有聲音時的圖示 */
}
在這份 CSS 中,我們做了以下處理:
- .control-btn 適用於所有自訂控制的按鈕。我們將按鈕設計為32px的正方形(靜音按鈕略微小一點示範也可行),移除了預設的背景和邊框,使其外觀乾淨,並將文字顏色設為透明以隱藏<button>內的預設文字(例如我們在 HTML 中寫了"播放"、"靜音"作為無樣式時的備援,但實際顯示會用圖示代替)。cursor: pointer讓滑鼠經過時顯示可點擊的手勢。:hover和:focus時降低不透明度以提供視覺反饋,這使得使用者將鼠標移上去時按鈕稍微變暗,好像被按下一樣。
- 播放/暫停按鈕圖示:利用 #playPauseBtn.paused 與 #playPauseBtn:not(.paused) 兩種選擇器,來對應按鈕不同狀態下的背景圖。當按鈕具有類別paused時,我們設定 background-image 為播放圖示(例如一個三角形的播放箭頭圖片);當沒有paused類別(表示目前在播放)時,背景圖則設為暫停圖示(兩條豎線的暫停符號圖片)。background-size: contain確保圖示在按鈕範圍內等比例縮放。
- 靜音按鈕圖示:類似地,使用#muteBtn.muted和:not(.muted)來設定兩種圖示——靜音時(有類別muted)顯示一個靜音喇叭圖示,非靜音時顯示一般音量喇叭圖示。寬高設為28px略小,以示不同按鈕可以獨立調整。
圖示素材:以上引用的icon-play.webp等圖片可由設計師提供,或使用現有圖庫的免費圖示。另一種替代方案是使用字型圖示(如 Font Awesome)或 SVG 矢量圖標。您可以在按鈕內放入 <i class="fa fa-play"> 之類的元素搭配字型圖示庫,或直接使用 <svg>。為簡化本教學,我們假定使用簡單的 PNG/SVG 圖片並透過 CSS background-image 引用。如果沒有定制圖示,也可暫時用按鈕文字(如播放/暫停)代替,確保功能先行。
進度條與音量滑桿樣式
對於<input type="range">類型的元素,瀏覽器預設樣式各異,我們可以透過 CSS 加以自訂。例如,將滑桿軌道設置顏色、高度,滑塊(thumb)設計成圓點等。不過,由於各瀏覽器需要使用不同的偽元素選擇器(如 ::-webkit-slider-thumb 及 ::-moz-range-thumb 等)來調整,我們在此給出簡單的範例設定:
/* 調整進度條和音量滑桿的基本外觀 */
input[type="range"] {
-webkit-appearance: none; /* 去除預設樣式 (Chrome/Safari) */
width: 100%;
max-width: 150px;
background: transparent;
cursor: pointer;
/* 將滑桿大致定位在中間,可視需要微調margin使其與其他元素對齊 */
margin: 0 5px;
}
/* 軌道樣式 (WebKit瀏覽器) */
input[type="range"]::-webkit-slider-runnable-track {
height: 4px;
background: #777;
border-radius: 2px;
}
/* 滑塊thumb樣式 (WebKit) */
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 12px;
height: 12px;
background: #fff;
border: 2px solid #555;
border-radius: 50%;
margin-top: -4px; /* 將thumb往上移,對齊軌道 */
}
/* 軌道樣式 (Firefox) */
input[type="range"]::-moz-range-track {
height: 4px;
background: #777;
border-radius: 2px;
}
/* 滑塊樣式 (Firefox) */
input[type="range"]::-moz-range-thumb {
width: 12px;
height: 12px;
background: #fff;
border: 2px solid #555;
border-radius: 50%;
}
以上 CSS 使進度條和音量滑桿在各主要瀏覽器上呈現較一致的外觀:一條細長的灰色軌道和一個白色圓形滑塊。有幾點需要解釋:
- -webkit-appearance: none 用於關閉 Chrome/Safari 等使用 WebKit 引擎的瀏覽器的預設樣式。Firefox 則不需要這項,但為一致性我們仍然指定一些共通屬性。
- 我們將滑桿寬度設為100%,並限定一個最大寬度(150px)防止在大螢幕上過長。您可以依據佈局需要調整這個值,或讓其 flex 自適應父容器。
- 透過偽元素選擇器 ::-webkit-slider-runnable-track 和 ::-moz-range-track 設定軌道高度與顏色,並用 border-radius 讓軌道有圓角邊緣。滑塊(thumb)部分則設為12px的圓形,使用白色背景和深色邊框以清晰可見。
- margin-top: -4px 這個技巧是讓 WebKit 瀏覽器的滑塊往上移一點,使其中心對齊 4px 高的軌道,優化視覺對齊。
應注意,不同瀏覽器對 range 輸入的 CSS 支援略有差異,但以上設定已涵蓋主流的 Chrome、Safari、Firefox。如需更華麗的樣式(例如滑過進度條顏色變化、在滑桿上顯示拖曳提示等),可以加入更多 CSS 或 JavaScript 邏輯,此處不贅述。
經過上述 CSS 調整,我們的播放器介面應該已初具雛形:自訂的按鈕和滑桿排列整齊、樣式統一,並使用我們選擇的圖示來代表各項功能。現在,介面外觀雖然有了,但按鈕點擊和滑桿互動還沒有任何作用。我們需要撰寫 JavaScript 程式碼,將這些控制元件與實際的播放功能連結起來,讓播放器真正"活"起來。
使用 JavaScript 控制播放器功能
到了最關鍵的部分:使用原生 JavaScript 操控 HTML5 媒體元素,實現我們自訂介面的各項功能。HTMLMediaElement(<video>和<audio>元素在 DOM 中的介面)提供了豐富的屬性、方法和事件,允許我們用腳本對媒體進行播放控制和狀態監聽。接下來,我們將一步步為自訂控制項添加事件監聽器,使它們能控制播放器的播放、暫停、跳轉、音量、速率以及全螢幕等功能。
在開始為各按鈕綁定功能之前,我們先要取得前面建立的各 DOM 元素引用,並初始化播放器狀態。例如,需要取得影片元素、控制列容器及各控制項按鈕/滑桿的元素。還記得我們在 HTML 中為每個元件都設定了id嗎?現在可以透過 document.getElementById() 來抓取它們。
另一件初始化要做的事是隱藏原生控制並顯示自訂控制列。正如先前討論的,當確定 JavaScript 可用時,我們要將video.controls屬性關掉,並移除控制容器的hidden類別以呈現我們的自訂UI。
下面的程式碼將完成上述初始化,以及實現播放/暫停按鈕的控制功能:
// 取得媒體元素和控制項元素
const video = document.getElementById("videoPlayer");
const audio = document.getElementById("audioPlayer"); // 若有音訊播放器
const videoControls = document.getElementById("videoControls");
const playPauseBtn = document.getElementById("playPauseBtn");
const progressBar = document.getElementById("progressBar");
const timeDisplay = document.getElementById("timeDisplay");
const muteBtn = document.getElementById("muteBtn");
const volumeSlider = document.getElementById("volumeSlider");
const speedSelect = document.getElementById("speedSelect");
const fullscreenBtn = document.getElementById("fullscreenBtn");
// 檢查瀏覽器是否支持 <video>(大多數現代瀏覽器都支援)
if (!!document.createElement('video').canPlayType) {
// 隱藏原生控制,顯示自訂控制列
video.controls = false;
videoControls.classList.remove("hidden");
}
// 播放/暫停按鈕點擊事件
playPauseBtn.addEventListener("click", () => {
if (video.paused || video.ended) {
video.play();
} else {
video.pause();
}
});
讓我們逐步解釋上述腳本:
- 首先利用 getElementById 抓取我們需要操作的所有元素,包括影片元素(video)、音訊元素(audio,若有使用)、控制列容器以及各個按鈕和滑桿。
- 接著,一個if判斷中使用了 document.createElement('video').canPlayType 來檢查瀏覽器對<video>的基本支援。如果支援的話,我們執行兩件事:video.controls = false 將影片的瀏覽器原生控制介面關閉;並將我們的控制容器元素移除hidden類別 (classList.remove("hidden")),使自訂控制列顯示出來。這段邏輯確保假如使用者的瀏覽器不支援 HTML5 視訊(極罕見的情況)或使用者停用了JavaScript,那麼我們的自訂控制不會無故顯示一個不能運作的介面,此時使用者仍可使用瀏覽器原生控制(因為我們只有在確認支援時才移除它們)。
- 最後,為播放/暫停按鈕註冊了一個點擊事件監聽器。當按鈕被點擊時,程式會檢查目前影片是否處於暫停 (video.paused) 或已結束 (video.ended) 狀態。如果是,則呼叫video.play()開始播放;否則(表示影片正在播放中),則呼叫video.pause()暫停之。這樣就實現了播放/暫停的切換。每次點擊按鈕,播放器都會在播放與暫停之間切換。
值得注意的是,在這個階段我們還沒有處理按鈕圖示的切換。我們的 CSS 設計是透過按鈕的類別來改變圖示,因此我們需要在影片開始播放或暫停時,調整playPauseBtn的類別。例如,當影片播放時應移除paused類別(顯示暫停圖示),暫停時則加上paused類別(顯示播放圖示)。我們可以透過監聽影片的play和pause事件來做到這一點:
// 根據播放狀態更新播放按鈕的圖示類別
video.addEventListener("play", () => {
playPauseBtn.classList.remove("paused");
});
video.addEventListener("pause", () => {
playPauseBtn.classList.add("paused");
});
<video>元素在調用play()和pause()時會分別觸發play與pause事件。我們利用這些事件來更新按鈕狀態,使圖示與實際播放狀態同步。現在,播放/暫停功能已完整:點擊按鈕可開始或暫停影片,且按鈕圖示會隨之改變。
更新進度條和時間顯示
有了播放進行,進度條應隨時間更新,使用者也可互動控制。為此,我們需要處理兩個方面:一是影片播放時及拖動時更新進度滑桿與時間顯示,二是當使用者拖曳或點擊進度滑桿時,讓影片跳轉到對應的時間。
HTMLMediaElement 提供了一些有用的屬性:video.currentTime 表示當前播放時間(以秒為單位),video.duration 表示影片總長度(秒)。還有一個 timeupdate 事件,在播放期間會週期性地觸發(通常數百毫秒間隔),通知當前播放時間更新。我們可以利用這個事件來更新進度條的位置和時間顯示。
另外,當影片元資料(例如長度)載入完成時,會觸發 loadedmetadata 事件。我們可以在這個事件上取得 video.duration,並設置進度滑桿的最大值。將滑桿max屬性設為影片總秒數,然後隨播放改變滑桿的value為目前秒數,滑桿就能精確表示進度比例。
讓我們為進度控制加入以下腳本:
// 當影片元資料已載入,設定進度條的最大值為影片總長度
video.addEventListener("loadedmetadata", () => {
progressBar.max = video.duration;
// 更新總時長顯示
timeDisplay.textContent = formatTime(video.duration) + " / " + formatTime(video.duration);
});
// 播放過程中更新進度條與時間顯示
video.addEventListener("timeupdate", () => {
if (!progressBar.getAttribute('max')) {
// 某些瀏覽器可能在loadedmetadata前開始播放,保險起見再設一次
progressBar.max = video.duration;
}
progressBar.value = video.currentTime;
// 更新當前時間顯示
timeDisplay.textContent = formatTime(video.currentTime) + " / " + formatTime(video.duration);
});
// 讓使用者拖曳進度條時跳轉播放位置
progressBar.addEventListener("input", () => {
video.currentTime = progressBar.value;
});
上述代碼實現了進度條與時間顯示同步:
- 在 loadedmetadata 事件中,我們將進度滑桿的最大值 (max) 設為影片長度(video.duration)。同時更新顯示的總時間。我們使用了一個函式 formatTime 來格式化秒數為「分鐘:秒」形式(該函式需我們自己撰寫,見下文)。舉例而言,如果影片長度為 90秒,則 formatTime(90) 輸出 "1:30"。timeDisplay.textContent 則設定為 "0:00 / 1:30" 這樣的格式(初始當前時間0:00,總長度1:30)。
- 在 timeupdate 事件中,每當影片播放進度更新,就執行回呼:我們先確保滑桿max已設定(有些行動裝置瀏覽器的loadedmetadata行為不一致,所以增加保護),然後將 progressBar.value 設為 video.currentTime,使滑塊對應影片當前秒數的位置。同時更新時間顯示,把現在時間和總長度都格式化後呈現出來。由於timeupdate頻繁觸發,我們這裡直接使用 textContent 覆蓋文字,對效能影響輕微可接受。
- 最後,監聽 progressBar 的input事件(range 在使用者拖動時連續觸發input事件)。當滑桿的值發生改變時,將影片的 currentTime 設為滑桿當前值。由於我們的滑桿值域正是0到影片長度秒數,這會讓影片跳轉到對應秒的位置。換句話說,用戶可以透過拖曳進度條來跳轉影片。
現在,我們需要定義一下 formatTime 函式。這個小函式將傳入的秒數轉為「分鐘:秒」的字串,秒數不足10時前面補0:
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return mins + ":" + (secs < 10 ? "0" : "") + secs;
}
有了它,我們的時間顯示就會是常見的格式了。
音量控制與靜音切換
接下來處理音量相關的控制項。HTML 媒體元素的 volume 屬性控制音量大小(範圍0.0至1.0),muted 屬性是一個布林值,表示是否靜音。還有一個有用的事件 volumechange 在音量或靜音狀態改變時觸發。
我們的界面提供了兩種音量操作:透過滑桿調整音量大小,和透過按鈕切換靜音/取消靜音。以下腳本實現這些功能:
// 音量滑桿調整事件
volumeSlider.addEventListener("input", () => {
video.volume = volumeSlider.value;
video.muted = false; // 調整音量時自動取消靜音(如適用)
});
// 靜音按鈕點擊事件
muteBtn.addEventListener("click", () => {
video.muted = !video.muted; // 取反音訊靜音狀態
});
// 當音量或靜音狀態變化時,更新介面顯示
video.addEventListener("volumechange", () => {
// 根據是否靜音,切換靜音按鈕的類別,以改變圖示
if (video.muted || video.volume === 0) {
muteBtn.classList.add("muted");
} else {
muteBtn.classList.remove("muted");
}
// 確保滑桿反映當前音量(如果是靜音但volume還有值,也可以選擇把slider暫時設0顯示)
volumeSlider.value = video.volume;
});
解釋:
- 音量滑桿:監聽input事件,每次用戶拖動滑桿就將影片的video.volume設為滑桿的值(0~1)。同時強制video.muted = false以取消靜音(有些使用者可能在靜音狀態下拉音量,我們讓它脫離靜音)。注意,volume屬性調整音量時不會自動改變muted狀態,所以我們手動取消靜音以保證一致性。
- 靜音按鈕:每次點擊時將video.muted屬性切換其布林值,也就是如果目前非靜音則靜音,反之則解除靜音。
- 介面同步:透過 volumechange 事件處理,它在volume或muted任何一者改變時都會觸發。我們在回呼中根據影片是否靜音或音量為0,來決定是否給muteBtn加上muted類別(這會對應CSS顯示靜音圖示)。同時,將volumeSlider.value更新為video.volume。特別地,如果使用者點擊靜音按鈕,我們需要反映在滑桿上(靜音並不改變volume值,只是不出聲音,所以volumeSlider可能還保留著舊值——這邊我們選擇不改變滑桿位置,仍顯示之前的音量值,這在一些UI中是常見的做法,以便使用者一按解除靜音就回到原音量)。如果你希望靜音時滑桿也移到0,可以在靜音發生時暫時把slider的value設0,但要留存之前的音量值以便取消靜音後恢復,這需要額外變數保存,不在此深入。
播放速率調整
我們的播放器提供播放速率選單,對應video.playbackRate屬性。此屬性預設為1.0,代表正常速度,可以設定0.5為0.5倍慢放,2.0為2倍快放,等等。更改playbackRate會立即影響影片播放速度。下面為速率選單變更的處理:
// 播放速率選單變更事件
speedSelect.addEventListener("change", () => {
video.playbackRate = parseFloat(speedSelect.value);
});
相當簡單,將選擇的值轉為浮點數賦給video.playbackRate即可。您可以根據需要擴充更多速度選項,或甚至提供一個數字輸入讓高級用戶輸入自訂速率。但要注意極端速率可能導致音訊不自然或瀏覽器無法順暢播放。
快轉、快退與停止功能(可選)
一般播放器也可能有快轉/快退按鈕(例如每點擊跳10秒)或一個停止按鈕(將播放停止並重設進度到開頭)。這些功能其實都可以透過操控currentTime實現:
- 快轉10秒:video.currentTime += 10;
- 快退10秒:video.currentTime -= 10;(但要確保不低於0)
- 停止:相當於暫停並重設進度到頭:video.pause(); video.currentTime = 0;
我們在此沒有專門在 HTML 介面加上這些按鈕,但原理如上,讀者可自行實作。例如,可以為快轉10秒增加一個按鈕,監聽點擊事件來執行上述程式碼。同時,重設進度後可以一併重設進度條的值(例如設為0)。這裡提供一個停止按鈕實作的範例,假設 HTML 加入了<button id="stopBtn">停止</button>:
const stopBtn = document.getElementById("stopBtn");
stopBtn.addEventListener("click", () => {
video.pause();
video.currentTime = 0;
progressBar.value = 0;
});
由於 HTMLMediaElement 並沒有內建停止的方法,我們手動暫停並將時間歸零。快進/快退按鈕也類似,操作 currentTime 增減即可。
全螢幕切換
最後,處理全螢幕按鈕。全螢幕需要使用瀏覽器的 Fullscreen API。標準的方法是對一個元素調用 requestFullscreen() 將其全螢幕顯示,退出全螢幕則呼叫 document.exitFullscreen()。我們希望點擊按鈕時,如果尚未全螢幕就進入全螢幕,如果已經全螢幕則退出。
首先,要檢查瀏覽器是否允許全螢幕操作(有些環境禁止全螢幕)。可以透過document.fullscreenEnabled布林值檢查,若為false,我們可以將按鈕隱藏或禁用。
其次,全螢幕時我們希望不僅影片充滿螢幕,也讓自訂控制列一起顯示。因此我們應對外層容器(例如videoPlayerContainer)調用requestFullscreen(),而不是直接對<video>。這樣容器中的所有內容(影片和控制列)都會一起進入全螢幕。
以下是全螢幕按鈕的腳本:
// 如果瀏覽器不支援全螢幕,隱藏全螢幕按鈕
if (!document.fullscreenEnabled) {
fullscreenBtn.style.display = "none";
}
// 全螢幕按鈕點擊事件
fullscreenBtn.addEventListener("click", () => {
if (document.fullscreenElement) {
// 已在全螢幕狀態,則退出
document.exitFullscreen();
} else {
// 非全螢幕,則進入
videoPlayerContainer.requestFullscreen().catch(err => {
console.log("無法進入全螢幕:", err);
});
}
});
解析:
- 我們檢查 document.fullscreenEnabled,如果為 false,將按鈕隱藏。絕大多數現代瀏覽器都支援,但某些老瀏覽器可能需要使用廢棄前綴方法(如 webkitRequestFullscreen 等)。在 2025 年,此屬性已被廣泛支援,但如果需要兼容古老瀏覽器,可加上對 document.webkitFullscreenEnabled 等的檢查,並在調用時用對應前綴方法。這裡我們簡化處理。
- 監聽按鈕點擊:使用 document.fullscreenElement 判斷目前是否有元素處於全螢幕狀態(若是,退出全螢幕)。如果不是,就對我們的播放器容器 videoPlayerContainer 調用 requestFullscreen() 方法進入全螢幕。特別注意,我們要取得對應容器元素的引用(在前面的 JavaScript初始化,可新增 const videoPlayerContainer = document.getElementById("videoPlayerContainer");)。在進入全螢幕的調用後,我們鏈接了一個.catch來捕捉可能的錯誤(比如用戶拒絕或瀏覽器策略不允許),以便至少打印錯誤信息。
額外提示:進入全螢幕後,可監聽fullscreenchange事件來偵測何時退出全螢幕,若想在退出時對UI做調整(例如隱藏控制列或復原一些樣式)。我們在此不特別處理。但可以注意的是,全螢幕模式下使用者移動滑鼠可能希望控制列隱藏/顯示,可透過CSS或JS控制,屬進階範疇。
經過以上步驟,我們已經為主要的自訂控制項都綁定了對應的行為。此時,我們的HTML5自訂播放器應該具備與瀏覽器原生播放器相當的核心功能:可以播放/暫停、拖動進度、調整音量、靜音、改變播放速度,以及全螢幕播放。更棒的是,整個界面風格可由我們掌控,可以融入網站的設計主題,甚至添加更多創意互動。
進階功能與擴充應用
基礎功能實作完成後,我們可以考慮進一步豐富播放器,增加一些進階的體驗。以下探討幾個常見擴充方向,並提供對應的實現思路:
播放列表(Playlist)
如果您的網站需要播放一系列音訊或影片(例如音樂專輯或一組教學影片),可以實作播放列表功能。在簡單的播放列表中,我們可以預先定義多個媒體檔案的路徑,然後在每次當前媒體結束(end)時,自動跳到下一個。
實現方法如下:建立一個包含多個 URL 的陣列,追蹤目前播放的索引。在影片元素的ended事件觸發時,更新索引並設置新的video.src,然後呼叫video.play()開始下一個。範例如下:
const playlist = [
"video1.mp4",
"video2.mp4",
"video3.mp4"
];
let currentIndex = 0;
// 當前影片播放結束時,播放下一個
video.addEventListener("ended", () => {
currentIndex += 1;
if (currentIndex >= playlist.length) {
currentIndex = 0; // 播放完最後一個後,可選擇重新開始或停留在最後
}
video.src = playlist[currentIndex];
video.play();
});
如上,我們定義了一個playlist陣列和currentIndex索引。在ended事件(影片播完)裡,索引加一,超出範圍則歸零(形成循環播放的效果,可依需求選擇是否循環)。然後設定影片的新來源並播放。當換片源時,loadedmetadata會再次觸發,進度條的max和時間顯示也會更新。我們的控制邏輯基本相同。您也可以為播放列表增加介面,例如顯示播放清單項目、讓使用者點擊選擇特定曲目。那將需要操作 DOM 列表並設定對應的currentIndex,原理與上述類似。
自訂圖示和風格細節
先前我們以 CSS 背景圖設定了播放、暫停、音量等圖示。開發者可進一步精細化這些圖示的呈現。例如:
- 更換圖示:使用網站品牌色彩風格的圖示,或在不同狀態使用動畫(如暫停鍵轉換成播放鍵的過渡效果)。只需在事件中改變按鈕的類別或 data-屬性,並配合 CSS 動畫/轉換即可達成。
- 控制列位置:可將控制列設定為浮動在影片下方中間,或覆蓋在影片底部。可透過 CSS 調整position和bottom、left等實現。如果覆蓋在影片上,建議在滑鼠移動或定時後隱藏控制列,可以監聽mousemove事件來觸發顯示/隱藏,提升沉浸感。
- 主題切換:如果網站有明暗模式,可以用 CSS 變數或不同的類別,切換控制列和圖示的色調。
- 載入動畫:影片緩衝時(例如網速慢出現延遲),可考慮顯示一個 loading 圖示。可以監聽waiting事件顯示動畫,playing事件隱藏動畫。
更換媒體來源
除了播放列表順序播放外,有時我們需要切換影片或音訊來源,例如提供不同解析度/畫質的影片切換按鈕,或手動選擇下一首歌曲。實現這類功能非常直接——透過更改video.src或audio.src屬性即可。換源後,如要立即播放,可呼叫video.play()。
舉例來說,假設我們有一個下拉選單讓使用者選擇畫質:
<select id="qualitySelect">
<option value="movie_hd.mp4">HD 畫質</option>
<option value="movie_sd.mp4">SD 畫質</option>
</select>
那麼 JS 處理可以是:
const qualitySelect = document.getElementById("qualitySelect");
qualitySelect.addEventListener("change", () => {
const currentTime = video.currentTime;
const isPaused = video.paused;
video.src = qualitySelect.value;
video.addEventListener("loadeddata", () => {
// 切換畫質後,維持原本的進度並狀態(播放/暫停)
video.currentTime = currentTime;
if (!isPaused) {
video.play();
}
}, { once: true });
});
這段程式碼示範了切換影片文件:我們暫存當前播放時間和狀態,然後更改src。監聽loadeddata(當新影片資料載入可播放時)事件,將影片跳轉到原本時間,如果先前在播放則繼續播放。這可以讓使用者無縫地從某畫質切換到另一畫質而不影響觀看進度。
多語言字幕切換
HTML5 <track> 標籤允許我們為影片提供字幕或標題文字軌。可以在 <video> 裡面加入多個 <track>,每個對應不同語言或類型(字幕、隱藏字幕等)。例如:
<video id="videoPlayer" ...>
<source src="movie.mp4" type="video/mp4" />
<track kind="subtitles" src="movie-en.vtt" srclang="en" label="English" default>
<track kind="subtitles" src="movie-fr.vtt" srclang="fr" label="Français">
</video>
在瀏覽器內建控制介面下,通常會自動提供字幕開關/選單。但在自訂介面中,字幕的顯示與切換需要我們透過 JS 來控制TextTrack。每個 <track> 在 DOM 中對應一個 video.textTracks[index] 物件。我們可以取得 video.textTracks列表,然後設定它們的mode屬性來顯示或隱藏字幕:
- track.mode = "showing" 顯示該文字軌字幕。
- track.mode = "hidden" 或 "disabled" 則隱藏它。
例如,我們可以建立一個字幕選單,讓使用者選擇語言:
<select id="subtitleSelect">
<option value="-1">關閉字幕</option>
<option value="0">English</option>
<option value="1">Français</option>
</select>
JavaScript 實作:
const subtitleSelect = document.getElementById("subtitleSelect");
subtitleSelect.addEventListener("change", () => {
const index = parseInt(subtitleSelect.value);
for (let i = 0; i < video.textTracks.length; i++) {
if (i === index) {
video.textTracks[i].mode = "showing";
} else {
video.textTracks[i].mode = "disabled";
}
}
});
這段程式碼會在使用者選擇選單時,遍歷所有字幕 track,將選中索引的那條設為顯示,其餘隱藏。如果選的是 -1(我們約定代表關閉字幕),則全部隱藏。執行此操作後,瀏覽器會自動在影片上疊加顯示 WebVTT 字幕內容(前提是 track 的 kind 是subtitles或captions,且瀏覽器支援字幕渲染)。
需要注意,不同瀏覽器對字幕呈現的樣式可能不一,且字幕檔需是 WebVTT 格式(副檔名 .vtt)。在進階應用中,你可以自訂字幕樣式(例如大小、顏色)透過 CSS 的 ::cue 選擇器。
若想整合外部字幕 API(例如串接某線上字幕資料庫),可以在影片播放時動態載入字幕檔並用 JavaScript 解析,在畫面上繪製字幕。這顯然比較複雜,通常建議使用 HTML5 track 內建功能或現有字幕函式庫。
問與答(FAQ)
在本章最後,我們來解答幾個開發自訂 HTML5 播放器時常見的疑問。
問:自訂播放器能在各大主流瀏覽器上正常運作嗎?跨瀏覽器相容性如何?
答:只要使用的是現代主流瀏覽器(Chrome、Firefox、Safari、Edge 等),HTML5 <audio> 和 <video> 元素以及相關的 Media API 都有良好支援。我們在文中提供的功能,如播放控制、音量、全螢幕等,皆採用標準的 API 實現,應可跨瀏覽器運作。需要注意的是,全螢幕 API 在較舊的瀏覽器版本曾經使用過廢棄的廠商前綴方法(如 webkitRequestFullscreen),如果需要兼容非常老的瀏覽器,可能要加上這些變體。音訊與影片格式方面,不同瀏覽器的解碼支援略有差異,例如 Safari 不支援 WebM、早期 Firefox 不支援 MP3 等,所以提供多種格式來源(MP4 + WebM + Ogg,或 MP3 + Ogg)是保持相容性的好做法。此外,行動裝置上 iOS Safari 對自訂播放器有一些特殊限制:在 iPhone 上影片通常會自動全螢幕播放,且只有使用內建控制才能切換 PIP(畫中畫)或 AirPlay。如果需要在這些環境提供完整體驗,可能要採用一些特殊屬性(如 playsinline 允許行動裝置上行內播放)或進一步的平臺檢測與調整。
問:如何取得並利用播放進度資訊?可以讓播放器記住上次播放到哪裡嗎?
答:播放進度可以透過監聽 timeupdate 事件並讀取 video.currentTime 取得。我們教程中已展示如何用它來更新進度條。若想儲存播放進度,例如讓使用者下次訪問時從上次位置繼續,可以在 timeupdate 裡定期將 currentTime 存入 localStorage 或後端數據庫。在下次載入播放器時,再從存儲中讀出時間並設定 video.currentTime 即可。請注意精度和頻率的取捨,每隔幾秒存一次即可,避免過於頻繁造成性能問題。另外,如果媒體內容較大且支援 HTTP Range,使用者也可以在任何位置開始播放,這對續播有利。
問:能否與字幕或其他資料來源的 API 整合?例如使用外部字幕或與第三方服務同步?
答:可以的。HTML5 媒體元素的 TextTrack API 已經覆蓋了字幕的大部分需求。如果有現成的字幕檔(例如 SRT 或 VTT),可直接加載為 <track> 使用。若要與外部服務整合(比如實時取得字幕翻譯、卡拉OK 歌詞逐字同步等),可以利用 timeupdate 搭配自己的資料:每當時間更新時從 API 獲取對應時間點的文字並顯示。這需要處理網路請求及文字顯示同步等,相對複雜,建議視需求選擇現有函式庫或服務。例如,有些第三方播放器庫(如 video.js、MediaElement.js 等)或字幕庫可以簡化整合過程。在我們這個純原生實作中,要實現類似功能,需要編寫額外的邏輯,但並非不可行。另外值得一提的是Media Session API,它允許網頁與裝置的媒體控制介面互動(如手機鎖屏控制、智慧喇叭等),也能設定歌曲資訊、封面、跳轉按鈕的行為。這算是進一步的整合,可以提高使用者體驗。
問:還有沒有必要使用現成的播放器框架或外掛?自己實作的優缺點是什麼?
答:這要視專案需求而定。自行實作的優點在於完全掌控介面與功能,沒有多餘的程式碼,體積小且易於定制,適合需要獨特UI/UX的項目。而著名的開源播放器(如 Video.js、MediaElement.js、JWPlayer 等)提供了豐富的功能和相容性封裝,包括更好的瀏覽器支援封層、播放串流協定(如 HLS/DASH)的插件、主題樣式和插件生態。如果你的需求包含複雜功能(廣告插入、DRM保護、播放速度很廣泛控制、以及各種瀏覽器坑的平滑處理),使用成熟庫可以節省大量時間,並減少跨瀏覽器問題。在一般情況下,原生 HTML5 足以滿足大部分網站內嵌影音的需求,本教學展示的方案就能提供穩定的體驗。如果未來需求增長,你也可以逐步擴充自己的實作或引入庫。重點是了解原理後,選擇最適合的工具。
結語
希望透過本篇教學,您已掌握如何以純原生的方式打造專屬的 HTML5 媒體播放器介面。從基本的播放控制到進階的播放列表和字幕支援,我們體驗了將想法轉化為實際代碼的過程。憑藉這些知識,您可以自由地將播放器介面調整到與您的網站設計渾然一體,同時提供使用者便利的影音互動。現在,拿起這份指南動手試試吧,讓您的網站媒體播放煥然一新!