Skip to main content

[JS30] Day11: Custom HTML5 Video Player

這堂課製作一個客製化的 video player,包含播放、音量、播放進度、播放速度、時間切換的基本操作。

HTML

要有 video 元素,才會出現預設的 video player,再加上我們要加入的功能在.player__controls 裡面

<div class="player">
<video class="player__video viewer" src="652333414.mp4"></video>

<div class="player__controls">
<div class="progress">
<div class="progress__filled"></div>
</div>
<button class="player__button toggle" title="Toggle Play"></button>
<input
type="range"
name="volume"
class="player__slider"
min="0"
max="1"
step="0.05"
value="1"
/>
<input
type="range"
name="playbackRate"
class="player__slider"
min="0.5"
max="2"
step="0.1"
value="1"
/>
<button data-skip="-10" class="player__button">« 10s</button>
<button data-skip="25" class="player__button">25s »</button>
</div>
</div>

JavaScript

首先,選取各個影片播放器元素

const player = document.querySelector(".player");
const video = player.querySelector(".viewer");
const progress = player.querySelector(".progress");
const progressBar = player.querySelector(".progress__filled");
const toggle = player.querySelector(".toggle");
const skipButtons = player.querySelectorAll("[data-skip]");
const ranges = player.querySelectorAll(".player__slider");

播放

video.paused 為影片目前的狀態。呼叫此函式時,如果是暫停的話,我們會呼叫video["play"](),呼叫後 video.paused 為否,下次再次呼叫此函式,會呼叫video["pause"]()

function togglePlay() {
const method = video.paused ? "play" : "pause";
video[method]();
}

video.addEventListener("click", togglePlay);

按鈕也會 video.paused 而有所變化

function updateButton() {
const icon = this.paused ? "►" : "❚ ❚";
toggle.textContent = icon;
}

video.addEventListener("play", updateButton);
video.addEventListener("pause", updateButton);

跳轉

在 skipButtons 的元素中,有著data-skip="-10"data-skip="25"的屬性(數字務必用雙引號包裹),我們透過 skip 函式來設定影片時間加上該元素的 dataset.skip,加上parseFloat轉為浮數點數字。

function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}

skipButtons.forEach((button) => button.addEventListener("click", skip));

parseFloat(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat

音量條與播放速度條

在 ranges 的元素中,有 name 為"volume"和"playbackRate",他們有著不同的min,max,step,value

透過他們的 name 屬性與 value 來去改變 video 元素,進度條通常要加上的監聽器為 change 和 mousemove,change 為滑鼠點擊放開時呼叫函式。

function handleRangeUpdate() {
video[this.name] = this.value;
}

ranges.forEach((range) => range.addEventListener("change", handleRangeUpdate));
ranges.forEach((range) =>
range.addEventListener("mousemove", handleRangeUpdate)
);

影片進度條

影片進度比例會是現在時間除以影片長度的百分比

function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}

video.addEventListener("timeupdate", handleProgress);

progressBar 的預設flex-basis為 50%,會隨著影片開始從 0%慢慢更新到 100%

flex-basis: https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis

影片進度拖移

mousedown 時,mousedown 變數為真,呼叫 scrub 函式,會設定 video.currentTime 為 scrubTime(觸發事件元素的滑鼠 x 位置 / 該物件的寬度 * 影片總長)。mouseup 時,mousedown 變數為否,不會呼叫 scrub 函式。

function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}

let mousedown = false;
progress.addEventListener("click", scrub);
progress.addEventListener("mousemove", (e) => mousedown && scrub(e));
progress.addEventListener("mousedown", () => {
mousedown = true;
});
progress.addEventListener("mouseup", () => {
mousedown = false;
});

offsetX @MDN