JavaScript30
第十一天的目標是自己建立一個影片撥放器,需含有撥放,快轉,調整音量大小,調整撥放速度,影片撥放進度條等功能
Github 檔案位置:11 - Custom Video Player
網頁一開始的樣子如下,就是影片撥放器的樣子,但目前沒有任何的功能
可以先去看看 最後的成品
我們今天要做的事情就是逐步的把功能建構完成
預計會以以下的順序來做
為整個畫面以及撥放的按鈕加上 click 事件監聽
這裡比較特別的是用了先前所提的三元運算子,以及 call 函式時所用到的 video[method]()
,[method]
的意義就是 video.play()
這樣寫可以簡化程式碼
function togglePlay(){
const method = video.paused ? 'play' : 'pause';
video[method]();
}
video.addEventListener('click', togglePlay);
toggle.addEventListener('click', togglePlay);
在可以撥放影片後,我們需要監聽影片的 play
和 pause
來改變撥放鍵的樣式
function updateButton(){
const icon = video.paused ? '>' : '|| ||';
toggle.textContent = icon;
}
video.addEventListener('play', updateButton); // 更新撥放按鈕為撥放
video.addEventListener('pause', updateButton); // 更新撥放按鈕為暫停
在監聽 click 事件時,要記得由於 skipButton 不只一個,所以要下 forEach
由於 HTML 的 dataset 已經有寫好 +25 及 -10 了,所以這裡可以直接將影片的時間加上設定好的數值
備註:由於 dataset.skip 值的型態是 string 所以需要轉型成 int
function skip(){
// console.log(this.dataset);
// console.log(typeof this.dataset.skip);
// dataset.skip 的 typeof 結果為 string
video.currentTime += (this.dataset.skip) * 1.0; // 強制轉型為數值
}
skipButtons.forEach(skipButton => skipButton.addEventListener('click', skip)); // 有兩個 要做 forEach
一樣是監聽 play 和 pause 兩個事件,再直接採用 HTML 裡面寫好的 name 去做屬性賦值
function handleRangeUpdate(){
// video 的 volume 可以控制音量
// video 的 playbackRate 可以控制速度
video[this.name] = this.value;
}
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
在這裡就是以目前影片的時間 / 整段影片的時間來算出進度條的百分比,再賦值到進度條的 CSS 屬性上
備註:timeupdate 事件在影片撥放時會持續觸發
function handleProgress(){
const percent = (video.currentTime / video.duration) * 100;
console.log(progressBar);
progressBar.style.flexBasis = `${percent}%`;
}
video.addEventListener('timeupdate', handleProgress); // 更新影片進度條
這裡一樣加上學過的事件監聽後,利用偵測鼠標點擊位置座標 / 總長度得到調整影片時間的百分比,再賦值給 video
function scrub(e){
// console.log(e.offsetX, progress.offsetWidth);
// e.offsetX 可以得到以進度條為範圍的 X 座標
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
let mousedown = false;
progress.addEventListener('click', scrub); // 點擊影片進度條
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e)); // 滑鼠按下才反應
/* Get Our Elements */
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');
function togglePlay(){
const method = video.paused ? 'play' : 'pause';
video.method();
}
function updateButton(){
const icon = video.paused ? '>' : '|| ||';
toggle.textContent = icon;
}
function skip(){
// console.log(this.dataset);
// console.log(typeof this.dataset.skip);
// dataset.skip 的 typeof 結果為 string
video.currentTime += (this.dataset.skip) * 1.0; // 強制轉型為數值
}
function handleRangeUpdate(){
// video 的 volume 可以控制音量
// video 的 playbackRate 可以控制速度
video[this.name] = this.value;
}
function handleProgress(){
const percent = (video.currentTime / video.duration) * 100;
console.log(progressBar);
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e){
// console.log(e.offsetX, progress.offsetWidth);
// e.offsetX 可以得到以進度條為範圍的 X 座標
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton); // 更新撥放按鈕為撥放
video.addEventListener('pause', updateButton); // 更新撥放按鈕為暫停
video.addEventListener('timeupdate', handleProgress); // 更新影片進度條
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(skipButton => skipButton.addEventListener('click', skip)); // 有兩個 要做 forEach
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub); // 點擊影片進度條
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e)); // 滑鼠按下才反應
以上是第十天的製作紀錄,如有錯誤或不足的地方還請多多指教 >.<
Custom HTML5 Video Player - #JavaScript30 11/30
[ Alex 宅幹嘛 ] 深入淺出 Javascript30 快速導覽 | Day 11:Custom Video Player