iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 11
0
Modern Web

寫JS30天系列 第 11

JS 30 - 11 - Custom Video Player

  • 分享至 

  • xImage
  •  

要自製一個video player
需要做的有

  1. 播放:點擊播放鍵、影片播放位置會play()pause()
  2. 控制音量的handler
  3. 控制播放速度handler
  4. 跳轉鈕
  5. 雙擊影片左/右,會往後/往前一定時間
  6. 進度條
  7. 全屏鈕

以下是html

<div class="player">
    <video class="player__video viewer" src="https://player.vimeo.com/external/194837908.sd.mp4?s=c350076905b78c67f74d7ee39fdb4fef01d12420&profile_id=164"></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="0.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 class="player__button full-screen" style="font-size: 24px;">&#x25AD</button>
    </div>
</div>

播放

首先先將包裹著的video的容器選起來

let player = document.querySelector('.player');  //容器
let toggle = player.querySelector('.toggle');  //播放鈕
let video = player.querySelector('.viewer');  //影片
let skipButtons = player.querySelectorAll('[data-skip]');  //skip按鈕
let handlers = player.querySelectorAll('[type="range"]');  //handler
let progressBar = player.querySelector('.progress');  //進度條
let currentBar = player.querySelector('.progress__filled');  //當前進度
let fullScreen = player.querySelector('.full-screen');  //全螢幕按鈕

設置點擊的監聽事件

video.addEventListener('click', togglePlay);  //點擊影片
toggle.addEventListener('click', togglePlay);  //點擊播放按鈕

video.addEventListener('play', changeButton);  //影片播放/暫停時,按鈕樣式改變
video.addEventListener('pause', changeButton);

要控制影片的播放就要偵側影片的播放狀態
並依照狀態播放或者暫停
然後還要修改播放鈕的圖示

//偵測video的播放狀態,並播放或暫停
function togglePlay() {
    // const method = video.paused ? 'play' : 'pause';
    // video[method]();
    video.paused ? video.play() : video.pause();
}

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

控制音量/播放速度的handler

由於我們拿到的handler是nodeList組成
所以要使用forEach()方法來監聽每個handler的changemousemove事件
change是改變的當下才會執行handlerChange()
mousemove讓我們在拖曳的時候也能執行

handlers.forEach(handler => handler.addEventListener('change', handlerChange));
handlers.forEach(handler => handler.addEventListener('mousemove', handlerChange));

兩個handler的name都已經放入控制video屬性volumeplaybackRate
所以我們就用video[this.name]來帶入屬性,讓他等於this.value
即可控制音量和播放速度

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

跳轉鈕和雙擊影片跳轉

監聽點擊跳轉鈕和雙擊影片的事件

skipButtons.forEach(skipButton => skipButton.addEventListener('click' ,skip));
video.addEventListener('dblclick', doubleClickScreen);

由於點擊跳轉鈕的時間寫在data-skip屬性內(string)
所以使用this.dataset.skip將字串叫出來
並使用pardeFloat()將字串轉成數字
如下

function skip() {
    video.currentTime += parseFloat(this.dataset.skip);
}
function doubleClickScreen(e) {
    const skipTime = (e.offsetX > this.offsetWidth / 2) ? '10' : '-10';
    video.currentTime += parseFloat(skipTime);
}

另外我們也要偵測點擊影片的位置
由於我們取得的element都是在player底下
因此只要e.offsetX大於整個寬度的一半就是往後快轉10s
小於則是倒帶10s

拉動進度條

首先我們先讓進度條可以跟著影片的播放而移動
css內使用的是flex-basis
所以可以使用百分比來顯示等前進度
我們只要
將時間還換成百分比即可
程式碼如下

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

progressBar.addEventListener('mousemove', drag);

但是只有偵測mousemove是不夠的
我們只要讓滑鼠在進度條上移動
就會影響其長度
因此用一個變數mousedown來存取mouse的狀態
預設是false
並偵測滑鼠點下與放開

let mousedown = false;
progressBar.addEventListener('mousemove', drag);
progressBar.addEventListener('mousedown', clickProgressBar);
progressBar.addEventListener('mouseup', clickProgressBar);

當滑鼠被點下或拿起是
會改變mousedown的狀態
這樣在拖曳的時候才會有反應

function drag(e) {
    if (mousedown) {
        const dragTime = (e.offsetX / progressBar.offsetWidth) * video.duration;
        video.currentTime = dragTime;
    }
}

function clickProgressBar(e) {
    mousedown = !mousedown;
}

但我們會發現在點擊的時候
影片並不會到指定的時間點
因此我們再添加下列程式碼

function clickProgressBar(e) {
    const dragTime = (e.offsetX / progressBar.offsetWidth) * video.duration;
    video.currentTime = dragTime;
    mousedown = !mousedown;
}

全螢幕

監聽全螢幕按鈕

fullScreen.addEventListener('click', toggleFullScreen);

由於全螢幕並未標準化
所以需要分別來設置他們全螢幕的方式
程式碼如下

function toggleFullScreen() {
    if (video.requestFullscreen) {
        video.requestFullscreen();
    } else if (video.mozRequestFullScreen) { /* Firefox */
        video.mozRequestFullScreen();
    } else if (video.webkitRequestFullscreen) { /* Chrome, Safari & Opera */
        video.webkitRequestFullscreen();
    } else if (video.msRequestFullscreen) { /* IE/Edge */
        video.msRequestFullscreen();
    }
}

關於全螢幕可以參考MDN

Demo
完整程式碼


上一篇
JS 30 - 10 - Hold Shift and Check Checkboxes
下一篇
JS 30 -12 - Key Sequence Detection
系列文
寫JS30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言