建立跨瀏覽器影片播放器
本文介紹了一個使用 Media 和 Fullscreen API 的基本 HTML 影片播放器。除了支援全屏播放外,該播放器還具有自定義控制元件,而不是僅使用瀏覽器預設控制元件。播放器控制元件本身不會進行除了基本功能實現之外的樣式設定;播放器的完整樣式將在未來的文章中進行介紹。
我們示例的影片播放器展示了一部名為“Tears of Steel”的開源電影片段,幷包含典型的影片控制元件。
HTML 標記
首先,讓我們看一下構成播放器的 HTML。
影片
我們的整個播放器包含在一個 <figure> 元素中。
<figure id="videoContainer">
在內部,我們首先定義 <video> 元素。
<video
id="video"
controls
preload="metadata"
poster="/shared-assets/images/examples/tears-of-steel-battle-clip-medium-poster.jpg">
<source
src="/shared-assets/videos/tears-of-steel-battle-clip-medium.mp4"
type="video/mp4" />
<source
src="/shared-assets/videos/tears-of-steel-battle-clip-medium.webm"
type="video/webm" />
<source
src="/shared-assets/videos/tears-of-steel-battle-clip-medium.ogg"
type="video/ogg" />
<!-- Offer download -->
<a href="/shared-assets/videos/tears-of-steel-battle-clip-medium.mp4"
>Download MP4</a
>
</video>
即使此播放器將定義自己的自定義控制元件集,但 controls 屬性仍會新增到 <video> 元素中,並且播放器的預設控制元件集稍後會透過 JavaScript 關閉。採用這種方式,即使停用了 JavaScript 的使用者(無論出於何種原因)仍然可以訪問瀏覽器的原生控制元件。
為影片定義了海報影像,並將 preload 屬性設定為 metadata,這會告知瀏覽器它應該只嘗試載入影片檔案的元資料,而不是整個影片檔案。這為播放器提供了影片時長和格式等資料。
為播放器提供了三種不同的影片源:MP4、WebM 和 Ogg。使用這些不同的源格式可以最大程度地提高所有支援 HTML 影片的瀏覽器上的相容性。有關影片格式和瀏覽器相容性的更多資訊,請參閱選擇影片編解碼器。
上面的程式碼允許在大多數瀏覽器中使用瀏覽器的預設控制元件集播放影片。下一步是也在 HTML 中定義一個自定義控制元件集,用於控制影片。
控制元件集
大多數瀏覽器的預設影片控制元件具有以下功能:
- 播放/暫停
- 靜音
- 音量控制
- 進度條
- 快進
- 全屏
自定義控制元件集還將支援此功能,並增加一個停止按鈕。
再次,HTML 非常簡單,使用一個無序列表,並將 list-style-type:none 設定為包含控制元件,每個控制元件都是一個設定了 float:left 的列表項。對於進度條,利用了 progress 元素。此列表插入在 <video> 元素之後,但位於 <figure> 元素內部(這對於稍後解釋的全屏功能很重要)。
<ul id="video-controls" class="controls" data-state="hidden">
<li><button id="play-pause" type="button">Play/Pause</button></li>
<li><button id="stop" type="button">Stop</button></li>
<li class="progress">
<progress id="progress" value="0"></progress>
</li>
<li><button id="mute" type="button">Mute/Unmute</button></li>
<li><button id="vol-inc" type="button">Vol+</button></li>
<li><button id="vol-dec" type="button">Vol-</button></li>
<li><button id="fs" type="button">Fullscreen</button></li>
</ul>
每個按鈕都賦予了一個 id,以便可以透過 JavaScript 輕鬆訪問。
控制元件最初透過 CSS display:none 隱藏,並將透過 JavaScript 啟用。同樣,如果使用者停用了 JavaScript,自定義控制元件集將不會出現,他們可以不受干擾地使用瀏覽器的預設控制元件集。
當然,這個自定義控制元件集目前是無用的,什麼也做不了:讓我們用 JavaScript 來改進一下。
最後,我們使用一個包含版權資訊的 <figcaption> 來關閉 <figure> 元素。
<figcaption>
© Blender Foundation |
<a href="http://mango.blender.org">mango.blender.org</a>
</figcaption>
</figure>
使用 Media API
HTML 帶有一個 JavaScript Media API,它允許開發者訪問和控制 HTML 媒體。此 API 將用於使上面定義的自定義控制元件集真正起作用。此外,全屏按鈕將使用 Fullscreen API,這是另一個 W3C API,用於控制 Web 瀏覽器以全屏模式顯示應用程式的能力。
設定
在處理單個按鈕之前,需要進行一些初始化呼叫。需要指向 HTML 元素的變數。
const videoContainer = document.getElementById("videoContainer");
const video = document.getElementById("video");
const videoControls = document.getElementById("video-controls");
const playPause = document.getElementById("play-pause");
const stop = document.getElementById("stop");
const mute = document.getElementById("mute");
const volInc = document.getElementById("vol-inc");
const volDec = document.getElementById("vol-dec");
const progress = document.getElementById("progress");
const fullscreen = document.getElementById("fs");
使用這些控制代碼,現在可以為每個自定義控制元件按鈕附加事件,使其具有互動性。其中大多數按鈕需要新增一個 click 事件監聽器,並對影片呼叫/檢查 Media API 定義的方法和/或屬性。
如前所述,現在需要停用瀏覽器的預設控制元件,並顯示自定義控制元件。
// Hide the default controls
video.controls = false;
// Display the user defined video controls
videoControls.setAttribute("data-state", "visible");
播放/暫停
playPause.addEventListener("click", (e) => {
if (video.paused || video.ended) {
video.play();
} else {
video.pause();
}
});
當在播放/暫停按鈕上檢測到 click 事件時,處理程式首先檢查影片當前是否暫停或已結束(透過 Media API 的 paused 和 ended 屬性);如果是,則使用 play() 方法播放影片。否則,影片必須正在播放,因此使用 pause() 方法將其暫停。
停止
stop.addEventListener("click", (e) => {
video.pause();
video.currentTime = 0;
progress.value = 0;
});
Media API 沒有 stop 方法,因此為了模擬它,影片會被暫停,並且其 currentTime(即影片的當前播放位置)和 <progress> 元素的位置會被設定為 0(稍後將詳細介紹 <progress> 元素)。
靜音
mute.addEventListener("click", (e) => {
video.muted = !video.muted;
});
靜音按鈕是一個切換按鈕,它使用 Media API 的 muted 屬性來靜音影片:這是一個布林值,指示影片是否靜音。為了使其能夠切換,我們將其設定為其自身的反值。
音量
volInc.addEventListener("click", (e) => {
alterVolume("+");
});
volDec.addEventListener("click", (e) => {
alterVolume("-");
});
定義了兩個音量控制按鈕,一個用於增加音量,另一個用於減小音量。建立了一個使用者定義的函式 alterVolume(direction) 來處理此問題。
function alterVolume(dir) {
const currentVolume = Math.floor(video.volume * 10) / 10;
if (dir === "+" && currentVolume < 1) {
video.volume += 0.1;
} else if (dir === "-" && currentVolume > 0) {
video.volume -= 0.1;
}
}
此函式利用了 Media API 的 volume 屬性,該屬性儲存影片的當前音量值。此屬性的有效值是 0 和 1 之間的任何值。該函式檢查 dir 引數,該引數指示音量是要增加(+)還是減小(-),並據此執行操作。該函式定義為以 0.1 的步長增加或減小影片的 volume 屬性,確保其不超過 0 或 1。
進度
在上面 HTML 中定義 <progress> 元素時,只將 value 屬性設定為 0。此屬性指示進度元素的當前值。它還需要設定一個最大值,以便正確顯示其範圍,這可以透過 max 屬性來完成,該屬性需要設定為影片的最大播放時間。這可以從影片的 duration 屬性中獲得,該屬性同樣是 Media API 的一部分。
理想情況下,當觸發 loadedmetadata 事件時(當影片元資料載入完成時),影片 duration 屬性的正確值將可用。
video.addEventListener("loadedmetadata", () => {
progress.setAttribute("max", video.duration);
});
不幸的是,在某些移動瀏覽器中,當 loadedmetadata 被觸發時——即使它被觸發了——video.duration 可能沒有正確的值,甚至沒有任何值。所以需要做些其他事情。下面將進一步介紹。
另一個事件 timeupdate 會在影片播放過程中定期觸發。此事件非常適合更新進度條的值,將其設定為影片 currentTime 屬性的值,該屬性指示當前播放進度。影片播放的進度。
video.addEventListener("timeupdate", () => {
progress.value = video.currentTime;
});
當觸發 timeupdate 事件時,progress 元素的 value 屬性被設定為影片的 currentTime。這個跨度有一個實心的 CSS 背景顏色,這有助於它提供與 <progress> 元素相同的視覺反饋。
回到上面提到的 video.duration 問題,當 timeupdate 事件被觸發時,在大多數移動瀏覽器中,影片的 duration 屬性現在應該具有正確的值。如果 progress 元素的 max 屬性尚未設定,則可以利用這一點來設定它。
video.addEventListener("timeupdate", () => {
if (!progress.getAttribute("max"))
progress.setAttribute("max", video.duration);
progress.value = video.currentTime;
});
注意:有關進度條和緩衝反饋的更多資訊和想法,請閱讀媒體緩衝、搜尋和時間範圍。
快進
大多數瀏覽器預設影片控制元件集的另一個功能是能夠單擊影片進度條以“跳到”影片中的不同點。也可以透過向 progress 元素新增 click 事件監聽器來實現此功能。
progress.addEventListener("click", (e) => {
if (!Number.isFinite(video.duration)) return;
const rect = progress.getBoundingClientRect();
const pos = (e.pageX - rect.left) / progress.offsetWidth;
video.currentTime = pos * video.duration;
});
這段程式碼使用單擊的位置(大致)來計算使用者在 progress 元素上單擊的位置,並透過設定其 currentTime 屬性將影片移動到該位置。如果影片的持續時間是 NaN 或 Infinity(當影片尚未載入時會發生這種情況),則它會避免設定 currentTime。
全屏
Fullscreen API 應該很簡單:使用者單擊按鈕,如果影片處於全屏模式:取消全屏,否則進入全屏模式。
如果 Fullscreen API 未啟用,則全屏按鈕將被隱藏。
if (!document?.fullscreenEnabled) {
fullscreen.style.display = "none";
}
全屏按鈕需要真正起作用。與其他按鈕一樣,會附加一個 click 事件處理程式,該處理程式會切換全屏模式。
fullscreen.addEventListener("click", (e) => {
if (document.fullscreenElement !== null) {
// The document is in fullscreen mode
document.exitFullscreen();
} else {
// The document is not in fullscreen mode
videoContainer.requestFullscreen();
}
});
如果瀏覽器當前處於全屏模式,則必須退出,反之亦然。有趣的是,必須使用 document 來退出/取消全屏模式,而任何 HTML 元素都可以請求全屏模式,此處使用 videoContainer,因為它也包含自定義控制元件,這些控制元件也應與影片一起顯示在全屏模式下。
結果
本教程隱藏了 CSS 部分,但您可以點選“播放”檢視完整原始碼。在下一部分,影片播放器樣式基礎,我們將探討這裡使用的一些有趣的 CSS 技術,並新增新的 CSS 使播放器看起來更美觀。
警告:示例影片可能會很大聲!
另見
<video>以供參考- HTML 影片和音訊瞭解更多技術
- HTML 音訊和影片元素支援的媒體格式