Skip to main content

[JS30] Day11: Custom HTML Video Player

HTML 部分#

Video and Audio APIs @ MDN - Learn web development

Video Element#

因為我對 HTML5 的 Video Element 不太熟,所以就自己在打了一次。

先來看一下 HTML5 中 Video element,預設有一些可用的屬性:

<video  autoplay  controls  muted  height="300px"  src="http://www.html5videoplayer.net/videos/toystory.mp4"></video>
<!--- autoplay: 載入自動播放- controls: 出現瀏覽器預設的播放器- loop: 是否重複播放- muted: 播放時預設靜音- src: 影片連結- height: 設定高度(不能設定百分比)- width: 設定寬度(不能設定百分比)- 等等...-->

HTML5 Video Element

由此可知,其實如果沒有要客制化播放器的話,直接在 <video> tag 中加上 controls 就可以使用瀏覽器內建的播放器了。

以下是 JS30 的 HTML Code#

原本的影片連結我不知道為什麼後來沒辦法正常播放,所以我換了一個連結:

//- pug .playervideo.player__video.viewer(src="http://www.html5videoplayer.net/videos/toystory.mp4").player__controls .progress .progress_filled button.player__button.toggle(title="Toggle Play") ►input.player__slider(type="range" name="volume" min="0" max="1" step="0.05" value="1")input.player__slider(type="range" name="playbackRate" min="0.5" max="2" step="0.1" value="1")button.player__button(data-skip="-10") « 10s button.player__button(data-skip="25") 25s »

再不添加任何 CSS 的情況下,畫面會長這樣:

img

CSS 部分#

簡單記錄一下幾個重點

重置 button#

/** * 利用 background, border, outline, padding 的設定重置 button */.player__button {  background: none;  border: 0;  line-height: 1;  color: white;  text-align: center;  outline: 0;  padding: 0;  cursor: pointer;  max-width: 50px;}

隱藏播放清單#

/** * 透過 transform: translateY 來隱藏播放清單 */.player__controls {  display: flex;  position: absolute;  bottom: 0;  width: 100%;  transform: translateY(100%) translateY(-5px);  transition: all 0.3s;  flex-wrap: wrap;  background: rgba(0, 0, 0, 0.1);}/* hover 時顯示播放清單 */.player:hover .player__controls {  transform: translateY(0);}

添加完 CSS 後畫面會長這樣子:

img

JS 部分#

HTML5 Video Element 主要繼承自 HTMLMediaElement,因此我們也可以從中找到可用的屬性:

const video = document.querySelector('video');
// 屬性(property)video.paused; // 影片是否為暫停狀態,ReadOnlyvideo.muted;video.volume; // from 0 to 1video.playbackRate; // 播放速度,預設是 1.0video.currentTime; // 可以取得和設定影片播放到的時間video.duration; // 取得影片的時間
// 方法(method)video.play();video.pause();
// 事件(event),其他事件可直接用 console.dir(video) 查看play;pause;timeupdate; // 當 video.currentTime 改變時會觸發

選擇所有相關元素#

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 視窗時可以播放或停止。使用 video.play()video.pause() 來控制播放或暫停:

// 播放或暫停影片function togglePlay() {  let playOrPause = video.paused ? 'play' : 'pause';  video[playOrPause](); // video.play() or video.pause()}
// 切換播放按鈕 iconfunction switchPlayButtonIcon() {  let icon = this.paused ? '►' : '❚ ❚';  toggle.textContent = icon;}
video.addEventListener('click', togglePlay);video.addEventListener('play', switchPlayButtonIcon);video.addEventListener('pause', switchPlayButtonIcon);toggle.addEventListener('click', togglePlay);

快轉與倒退#

使用 video.currentTime 來取得並設定當前影片播放到的時間點。

function skip(e) {  video.currentTime += Number(e.target.dataset.skip);}skipButtons.forEach((skipButton) => {  skipButton.addEventListener('click', skip);});

調整音量和播放速度#

使用 video.volumevideo.playbackRate 來控制播放的音量(0~1)和播放速度(預設是 1.0):

function handleRangeUpdate(e) {  video[e.target.name] = e.target.value;}ranges.forEach((rangeInput) => {  rangeInput.addEventListener('input', handleRangeUpdate);});

進度條相關函式#

使用 video.duration 可以取得影片的時間長度,因此我們可以用 (video.currentTime/video.duration) 知道目前影片播放了多少百分比,接著利用 progressBar.style.flexBasis 來改變進度條的長度:

// 顯示當前播放進度function showCurrentProgress() {  let progressPercent = (video.currentTime / video.duration) * 100;  // 利用 flex-basis 改變 progress bar 長度  progressBar.style.flexBasis = progressPercent + '%';}// 當 video.currentTime 改變時會觸發 timeupdatevideo.addEventListener('timeupdate', showCurrentProgress);

當我們要透過點擊進度條來改變播放時間時,要計算使用者點擊進度條位置的長度(e.offsetX)和總長度(progress.offsetWidth)的百分比,得到百分比後,再給回 video.currentTime

// 點擊進度條改變當前播放進度function changeCurrentProgress(e) {  // console.log('offsetParent', e.target.offsetParent)  let timeAtProgressBar = (e.offsetX / progress.offsetWidth) * video.duration;  video.currentTime = Number(timeAtProgressBar);}progress.addEventListener('click', changeCurrentProgress);

Day13: Slide In on Scroll 也會用到 element.offset 的屬性,因為offset是以外層容器左上角為原點,因此建議在使用offset前還是先用 offsetParent 看一下相對的外層容器指的是誰。

完成作品#

Day11: Custom HTML Video Player @ PJCHENder CodePen

參考資料#