본문 바로가기
DEV/JS30

[JS30] day 11 - Custom HTML5 video player

by newjp 2021. 12. 28.

기본 HTML 비디오 플레이어 커스텀✂️

HTML

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

    <div class="controls">
        <div class="progress">
            <div class="progress_bar"></div>
        </div>
        <div class="buttons">
            <button><i class="fas fa-play toggle"></i></button>
            <button data-skip=10><i class="fas fa-forward"></i></button>
            <button><i class="fas fa-volume-up volume_mute"></i></button>
            <input class="volume_control player__slider" type="range" name="volume" min="0" max="1" step="0.05" value="1">
            <button class="fullscreenBtn"><i class="fas fa-expand"></i></button>
        </div>
    </div>
</div>

 

CSS

.player:fullscreen {
  max-width: none;
  width: 100%;
}

input[type=range] {...}
  • fullscreen이 되었을 때 속성(:)을 정의해 준다
  • input[type=range]처럼 css에서 input 타입별로 선택 할 수 있음

 

JS

const mute = document.querySelector('.volume_mute');
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress_bar');
const toggle = player.querySelector('.toggle');
const skipButton = player.querySelector('[data-skip]');
const ranges = player.querySelector('.player__slider');
const fullBtn = player.querySelector('.fullscreenBtn');

function togglePlay() {
    const method = video.paused ? 'play' : 'pause';
    video[method](); // 조건문결과가 string으로 나오기 떄문에 video[play] 역할을 가짐
}

function updateButton() {
    if (toggle.classList.contains('fa-play')) {
        toggle.classList.remove('fa-play');
        toggle.classList.add('fa-pause');
    } else {
        toggle.classList.remove('fa-pause');
        toggle.classList.add('fa-play');
    }
}

function skip() {
    // console.log(this.dataset); // dataset은 지금 객체가 가지고 있는 data값을 알려줌
    video.currentTime += parseFloat(this.dataset.skip); // 실제 스킵
}

function handleRangeUpdate() {
    // console.log('dd')
    video[this.name] = this.value;
}

function handleProgress() {
    const percent = (video.currentTime / video.duration) * 100; // 현재 시간위치 값 계산
    console.log(percent)
    progressBar.style.flexBasis = `${percent}%`;
}

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

function togglemute() {
    console.log('I want to mute this video!!!')
    if (mute.classList.contains('fa-volume-up')) {
        mute.classList.remove('fa-volume-up');
        mute.classList.add('fa-volume-mute');
    } else {
        mute.classList.remove('fa-volume-mute');
        mute.classList.add('fa-volume-up');
    }
}

function goFullscreen() {
    console.log("클릭")
    if (!document.fullscreenElement) {
        player.requestFullscreen();
    } else {
        document.exitFullscreen();
    }
}

video.addEventListener('click', togglePlay);
toggle.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);

skipButton.addEventListener('click', skip);

ranges.addEventListener('change', handleRangeUpdate);
ranges.addEventListener('mousemove', handleRangeUpdate);

mute.addEventListener('click', togglemute);

let mouseDown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mouseDown && scrub(e));
progress.addEventListener('mousedown', () => mouseDown = true); 
progress.addEventListener('mouseup', () => mouseDown = false); 

fullBtn.addEventListener('click', goFullscreen);
  • 변수.classList.contains를 통한 클래스 확인으로 fontawsome class를 add-remove 해 버튼 변경
  • parseFloat : Float로 바꿔준다
  • js에서 요소 선택 방법은 document.queryselect 등으로 받아와 변수에 저장하는 것

 

[아쉬웠던 점 및 보완해야 할 점😥]

input range에서 progress 바로 볼륨 상태를 나타내고 싶음 (프로그레스 바와 동일하게 하면 될 듯)

유튜브의 플레이 창을 보고 따라했으나 미흡한 디자인...

mute버튼을 hover하면 volume control이 등장하기

mute버튼 클릭 시 토글 되는 아이콘의 크기에 따라 볼륨 컨트롤 바가 움직이는 것이 거슬림

커서를 video 밖으로 내보냈을 때는 controls 표시 X (밑으로 내려가게 하고 .player에서 overflow: hidden 주면 될 듯)