0%

JavaScript30-Custom-Video-Player-11

今天突然思考一個問題,
有什麼事情是現在一定要做的,不做會後悔的事

是應該好好充實自己,
把所有休假的時間都拿來精進自己的能力,
還是應該好好享受年輕的時候,
還有體力可以玩。

常常看到一些農場文章上寫著。
畢業之後,一定要成為怎樣的人掌握怎樣的能力。
男人在25至30歲之間的最應該做的事情有哪些呢?
三十歲前你一定要培養這八種能力。
四十歲,日子更好過的五種工作法。

是不是真的要照著他們說的才可以,成為大家口中的『成功』,
後來想想好像不盡然,
就算真的具備這些,似乎也需要很大的運氣。
可以到好公司,可以有好的職位。
職場上的努力似乎沒有絕對的正相關,
但想到這裡就覺得,難道我要就這樣慢慢來,一天過一天嗎?

其實好像也不是這樣,如果在一家小公司當到主管會比較好呢?
還是去google, facebook, apple,那種Top10當員工,
雖然能去google之類的 薪水應該也比在台灣當主管高。
但我想我嚮往的是,不斷的挑戰自己,
用實力來說話,
至於領導、管理職真的太看運氣了,反正有實力的人不會拿到低薪。
就算拿到低薪,也是會被看到的。
就像NBA 的 Anthony Davis教練說的一樣,
有實力的人到最後都會被看見的。
所以我們一起衝刺吧!!

讓自己在陰暗處當寶石,閃耀著有一天會有人知道自己的好,
一直維持好的心態,我想那些要具備的能力。
已經不是重點了。

11 - Custom Video Player

首次上傳:2020/10/21

主題

介紹如何使用HTML5的video tag來完成各種播放器功能,
播放/暫停、快進/快退、音量控制、速率控制等…

步驟

Step1. 基本設定

作者已經有將基礎的css及html tag設定好,僅需針對各項目的功能開始進行js撰寫即可,
但這邊我有將背景色調調整,並把對應icon改用font-awesome來顯示(原本是文字符號)。

由於寫到最後已經很多寫法跟原作者的方法不太一樣,所以接著各功能會再稍微備註為何這麼寫。

Step2. 播放/暫停按鈕

為了在整個播放器範圍及點擊播放按鈕時能播放/暫停,
先針對這兩個元素做addEventListener
並在togglePlay()中使影片產生對應動作&更換圖示,
比較特別的是使用了video[method]的寫法,來直接操作video的屬性,
直接用影片是否已暫停paused來做判斷。

1
2
3
4
5
6
7
8
9
10
11
12
13
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
const icon = video.paused ? `<i class="icon-play"></i>` : `<i class="icon-pause"></i>`;
toggle.innerHTML = icon;
video[method]();
}

### Step3. 音量/速率操作
在HTML中已經定義好對應的`input-range`標籤,
在這裡只需要做監聽並取屬性值來操作就好了!
````html
<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"

在javascript的部分,ranges是透過querySelectorAll來取得的,
所以可以用forEach來把所有range加上addEventListener
也因為range是拖曳條,除了click外,也必須要監聽mousemove
而name的命名volumeplaybackRate也就是video本身的屬性,直接使用。

1
2
3
4
5
6
7
function handleRangeUpadte() {
video[this.name] = this.value;
}
ranges.forEach(range => {
range.addEventListener('change', handleRangeUpadte);
range.addEventListener('mousemove', handleRangeUpadte);
})

Step4. 快進/快退操作

一樣也在HTML中的input定義好對應的秒數了,只須取出使用。

1
2
<button data-skip="-10" class="player__button skip_left"><i class="icon-backward"></i></button>
<button data-skip="25" class="player__button skip_right"><i class="icon-forward"></i></button>

在javascript的部分,原本的寫法只有點擊後觸發,
因為我有加上鍵盤觸發的動作,所以將skip加上了一個參數direction來判斷,
skipButtons也跟Step3的ranges一樣用forEach來加上監聽效果,
快進快退的作法是取出input中設定的data-skip後透過currentTime來調整影片時間。

Step5. 進度條顯示

使用video的currenTimeduration計算出進度%數,
再透過CSS改變進度條的色塊%數,值得一提的是作者有說到兩個監聽參數:
timeupdateprogress都可以做為影片時間變動時的觸發條件,
我稍微小測試後發現,使用progress會在載入時就將進度顯示在正確位置,
timeupdate必須在啟動播放後才會去抓到正確的位置,
可以將CSS中的flexBasis預設設為50%來觀察這兩者的差別。

1
2
3
4
5
function handleProgress() {
const precent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${precent}%`;
}
video.addEventListener('progress', handleProgress);

Step6. 進度條操作

在影片的進度條上,做點擊切換段落,或著是按著滑動片段,
分解動作會有:點擊按住並移動這兩種觸發條件,
為了要讓function能同時判斷兩種狀態,必須要將其中一個條件設flag,
這裡就將mousedown做了一個flag來操作狀態,
並利用e.offsetX的位置及progress.offsetWidth寬度與影片總長來操作當前秒數。

監聽的部分,因為原本重複寫了四次addEventListener
所以我把會使用到的event寫在一個陣列裡面,使用forEach去執行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let mousedown = false;
function scrunb(e) {
const mouseType = e.type;
if (mouseType === 'mousedown') { mousedown = true; }
if (mouseType === 'mouseup') { mousedown = false; }
if (mouseType === 'click' || mouseType === 'mousemove' && mousedown) {
const scrunbTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrunbTime;
}
}
const progressEvents = ['click', 'mousemove', 'mousedown', 'mouseup'];
progressEvents.forEach(progressEvent => {
progress.addEventListener(progressEvent, scrunb);
})

Step7. 全螢幕

作者最後有提到的小功能,他說留給我們自己去研究。
首先在HTML中加上對應的功能按鈕與圖標(就是這個放大圖標讓我去用font-aswsome的XD)

1
<button class="player__button fullScreen" title="Full Screen"><i class="icon-fullscreen"></i></button>

然後再javascript中加入這段,多個判斷是為了不同的瀏覽器而寫,
值得一提的是,不用對取消全螢幕特別做處理,預設就會有esc關閉及對應的關閉icon了,
但如果有特別需求可以使用exitFullscreen()來關閉。

1
2
3
4
5
6
7
8
9
10
11
12
function fullScreen() {
if (video.requestFullscreen) {
video.requestFullscreen();
} else if (video.msRequestFullscreen) {
video.msRequestFullscreen();
} else if (video.mozRequestFullScreen) {
video.mozRequestFullScreen();
} else if (video.webkitRequestFullscreen) {
video.webkitRequestFullscreen();
}
}
fullScreenBtn.addEventListener('click', fullScreen);

HTML5語法&備註

Video & Media Element

這次的主軸是HTML的video標籤,所以滿多操作都是直接操作video的屬性,
例如偵測暫停的paused或是當前播放時間currentTime
但其實這些屬性並非video獨有的,而是HTML Media Element,好比說audio也會有。

參閱:
MDN-Video
MDN-HTMLMediaElement

JavaScript語法&備註

屬性使用

在Step2中有使用video[method]()的方法來操作屬性,
其實相關的操作方法就等同於video.play(),但不能寫成video.method()
因為這樣就變成呼叫video底下的function method了,
所以使用中括號[]包起來的會自動變成字串,可以避免掉這樣的問題。

HTMLElement.dataset

在Step4中使用到的,使用dataset可以取得htmlTag中的data-*屬性!

參閱:MDN-

Event.preventDefault()

在Step8中使用到的,這個方法是將取消事件(如果事件可取消),
這次使用的場景是於網頁瀏覽器中按下空白,預設會將網頁捲到底部,
但我希望只要啟動我的播放/暫停功能就好不要捲動,就可以使用。

參閱:MDN-Event.preventDefault()
MDN-Event.preventDefault()

探索

本次的探索滿多,都已經寫在Step中了,
修改了播放器樣式及部分色調調整,對重複的監聽與變數整理,
加入了全螢幕效果以及鍵盤操作功能。

其他

終於踏出JavaScript30 2/3的第一步,
最近好多事,一直沒能好好靜下心來進修,
除了JS30,之前預購的一些CSS課程也要陸續上線了,
稍微覺得時間有點不夠用外,也開始容易分心了XD,
畢竟CSS等設計相關的課程看起來比較華麗啊哈哈哈。

加油持續把這系列練習完!!

[DEMO]