Video Control(JS, scss, pug)

김종민·2022년 11월 8일
0

Youtube

목록 보기
19/23

들어가기
JS를 이용해서, watch.pug에 비디오 controler를 만들어본다.
play, mute, fullScreen등등.
JS를 다시 복습하고 익혀 보도록 한다.


1. src/views/watch.pug


---------부분은 참고만 하라고 남겨둠.

extends base.pug

----------------------------------------------------
//- block head 
//-     title Watch | JmTube
-------------------------------------------------------
block content
    div#videoContainer
        video(src="/" + video.fileUrl)
        ///video 태그를 이용해 비디오파일을 불러준다.
        
        div#videoControls.videoControls
        ///#은 JS에서 사용하기위한 태그
        ///.은 scss에서 사용하기 위한 태그
        ///#은 scss에서도 사용가능한 태그(중복사용 가능)
            div.videoControls__play
                span#play.videoControls__playBtn
                    i.fas.fa-play
                    ///#은 JS에서 사용, .은 scss에서 사용
                    ///i.fas.fa-play은 base.pug에서 
                    ///import한 awesome icon을 사용하는것.
                div.videoControls__time
                    span#currenTime 00:00
                    span  / 
                    span#totalTime 00:00
                    
            input(type="range",step="1", value="0", min="0")#timeline.videoControls__timeline
            ///type이 rangef로 비디오가 얼마나 play됬는지 보여주는 바임. #이랑, .으로 js및 scss와 연결이 된다.
            
            div.videoControls__volume
                input(type="range",step="0.1", value=0.5, min="0", max="1")#volume
                span#mute
                    i.fas.fa-volume-up
            div
                span#fullScreen
                    i.fas.fa-expand
 --------------------------------------------------
    //-
        div
            p=video.description
            small=video.createdAt
        div
            small Uploaded by 
                a(href=`/users/${video.owner._id}`)=video.owner.name
        if String(video.owner._id) === String(loggedInUser._id)
            a(href=`${video.id}/edit`) Edit Video →
            br
            a(href=`${video.id}/delete`) Delete Video →
 ----------------------------------------------------------
 
block scripts
    script(src="/static/js/videoPlayer.js") 
    ///this pug 파일에 적용될 js파일을 불러줌.
--------------------------------------------------------
    
    //- div
    //-     h1=video.title
    //-     p=video.description
    //-     small=video.createdAt

    //- div 
    //-     small=video.owner.email 
    //-     br
    //-     small Uploaded by 
    //-             a(href=`/users/${video.owner._id}`) #{video.owner.username}
    //- each hashtag in video.hashtags 
    //-         li=hashtag
    //- h3 #{video.views} #{video.views === 1 ? "view" : "views"}
    //- if String(video.owner._id) === String(loggedInUser._id)
    //-     a(href=`${video.id}/edit`) Edit Video →
    //-     br
    //-     a(href=`${video.id}/delete`) Delete Video →
 --------------------------------------------------------

2. src/client/js/videoPlayer.js

const video = document.querySelector('video')
const playBtn = document.getElementById('play')
const playBtnIcon = playBtn.querySelector('i')
const muteBtn = document.getElementById('mute')
const muteBtnIcon = muteBtn.querySelector('i')
const volumeRange = document.getElementById('volume')
const currenTime = document.getElementById('currenTime')
const totalTime = document.getElementById('totalTime')
const timeline = document.getElementById('timeline')
const fullScreenBtn = document.getElementById('fullScreen')
const fullScreenIcon = fullScreenBtn.querySelector('i')
const videoContainer = document.getElementById('videoContainer')
const videoControls = document.getElementById('videoControls')
///pug 파일에서 #태그가 붙은 부분은 connect해줌.
/// video태그는 querySelector로 연결됨을 확인.
///그리고 playBtnIcon같은 경우는 #play아래 부분의 i.fas-fa-play
///부분은 connect하는것, 위의 태그인,
///playBtn.querySelector('i')로 connect한다.
///muteBtnIcon, fullScreenIcon도 마찬가지 방법임.


let controlsTimeout = null
let controlsMovementTimeout = null
let volumeValue = 0.5
///위의 3개는 global로 설정해서, 각각의 함수들이 getter, setter
///할 수 있게 함.
/// getter, setter은 값을 받고, 수정가능하게 하는거.

video.volume = volumeValue
///video 볼륨은 global로 설정한 volume으로 설정해 줌.

const handlePlayClick = (e) => {
  if (video.paused) {
    video.play()
  } else {
    video.pause()
  }
  //playBtn.innerText = video.paused ? "Play" : "Pause";
  playBtnIcon.classList = video.paused ? 'fas fa-play' : 'fas fa-pause'
}
///playBtn을 click했을떄, 작동되는 함수.
///video가 pause인지 play인지 여부에 따라, playBtnIcon의
///class가 (awesomeIcon)가 바뀌게 설정해 놓는다.

const handleMuteClick = (e) => {
  if (video.muted) {
    video.muted = false
  } else {
    video.muted = true
  }
  //muteBtn.innerText = video.muted ? "Unmute" : "Mute";
  muteBtnIcon.classList = video.muted
    ? 'fas fa-volume-mute'
    : 'fas fa-volume-up'
  volumeRange.value = video.muted ? 0 : volumeValue
}
///muteBtn을 click했을떄, 작동되는 함수.
///mute가 true인지 false인지 여부에 따라, playBtnIcon의
///class가 (awesomeIcon)가 바뀌게 설정해 놓는다.
//. volumeRange 값 역시, 연결해 준다.

const handleVolumeChange = (event) => {
  const {
    target: { value },
  } = event
  if (video.muted) {
    video.muted = false
    muteBtn.innerText = 'Mute'
  }
  volumeValue = value
  video.volume = value
}
///const volumeRange = document.getElementById('volume')
///이거를 connect해서, 
///volumeRange.addEventListener('input', handleVolumeChange) 
///connect함.
/// event발생시 value값을 target으로 얻는다.
///그 값을 video.volume에 넣어주고,
///volumeValue 값에 넣어준다.
///volumeValue는 위에 global로 설정해 놓았음.
///video.volume은 video player의 볼륨을 말한다.

const formatTime = (seconds) =>
  //new Date(seconds * 1000).toISOString().substr(11, 8);
  new Date(seconds * 1000).toISOString().substr(14, 5)
///요것은 video의 total시간 및 currentTime의 값은
/// 00:00:00의 형식으로 포맷해주는 함수.
/// 2015-12-20 14:34:23 ... 으로 나오는 new Date 값을
/// 14번쨰부터 5개를 뽑아낸다고 생각하면 된다.

const handleLoadedMetadata = () => {
  totalTime.innerText = formatTime(Math.floor(video.duration))
  timeline.max = Math.floor(video.duration)
}
///video.addEventListener('loadeddata', handleLoadedMetadata)
///video 파일의 전체 상영시간을 load해줌
///totalTime의 innerText를 video.duration을 불러줌으로
///전체 상영시간으로 찍힘.
///그리고 watch.pug의 timeline.max값 역시,
///video의 전체시간으로 찍힘.
/// formatTime은 함수로써, 00:00:00으로 표시되게 하는 함수.
///밑에서 만들어 놓았음.
///Math.floor은 소수점 아래를 버리게 해줌.

const handleTimeUpdate = () => {
  currenTime.innerText = formatTime(Math.floor(video.currentTime))
  timeline.value = Math.floor(video.currentTime)
}
///현재 몇분 상영되었는가를 나타내주는 함수.
///video.addEventListener('timeupdate', handleTimeUpdate)
///video 태그에 addEvent해준다는 것을 명심할것.

const handleTimelineChange = (event) => {
  const {
    target: { value },
  } = event
  video.currentTime = value
}
///상영중인 video를 플래이var에서 이리저리 옮기는것


const handleFullscreen = () => {
  const fullscreen = document.fullscreenElement
  if (fullscreen) {
    document.exitFullscreen()
    //  fullScreenBtn.innerText = "Enter Full Screen";
    fullScreenIcon.classList = 'fas fa-expand'
  } else {
    videoContainer.requestFullscreen()
    // fullScreenBtn.innerText = "Exit Full Screen";
    fullScreenIcon.classList = 'fas fa-compress'
  }
}
///fullScreen 버튼을 클릭함으로써 fullScreen을 true/false
///하는 함수.
/// const fullscreen은 화면이 현재 fullscreen인지 아닌지
///펀별하는것.
///fullscreen여부에 따라 아이콘도 바꾸어준다.

const hideControls = () => videoControls.classList.remove('showing')
///video화면에 마우스가 있는지 없는지 여부에 따라
///watch.pug파일에 showing이라는 class 를
///제거해 주는 함수.
///비디오에 마우스를 가져다대면, controls보여지는 것
/// &.showing이면 opacity:1, 아닐떄, opacity:0으로
/// scss에서 설정해 준다.

const handleMouseMove = () => {
  if (controlsTimeout) {
    clearTimeout(controlsTimeout)
    controlsTimeout = null
  }
  if (controlsMovementTimeout) {
    clearTimeout(controlsMovementTimeout)
    controlsMovementTimeout = null
  }
  videoControls.classList.add('showing')
  controlsMovementTimeout = setTimeout(hideControls, 3000)
}
///맨 위에 global로 
///let controlsTimeout = null
///let controlsMovementTimeout = null
///설정해 놓았음.
///마우스가 video에 있는지 없는지에 따라 showing이라는 class를
///보여주고 숨기는것. 
///그냥 hover로 설정하면 바로 끝남 ㅠㅠ

const handleMouseLeave = () => {
  controlsTimeout = setTimeout(hideControls, 3000)
}
///mouse가 video화면에서 벗어났을때, 3초후에 hideControls
///함수가 실행되게 한다.


playBtn.addEventListener('click', handlePlayClick)
muteBtn.addEventListener('click', handleMuteClick)
volumeRange.addEventListener('input', handleVolumeChange)
//video.addEventListener("loadedmetadata", handleLoadedMetadata);
video.addEventListener('loadeddata', handleLoadedMetadata)
video.addEventListener('timeupdate', handleTimeUpdate)
videoContainer.addEventListener('mousemove', handleMouseMove)
videoContainer.addEventListener('mouseleave', handleMouseLeave)
timeline.addEventListener('input', handleTimelineChange)
fullScreenBtn.addEventListener('click', handleFullscreen)
//video.addEventListener("mousemove", handleMouseMove);
//video.addEventListener("mouseleave", handleMouseLeave);

///맨위에서 pug파일과 연결한 단어들에 addEventListener를
///붙여서 동작을 넣는다. 
/// 버튼같은 경우는 'click'을 넣고 볼륨바,videoTimeLine같은
/// 바는 'input'으로 넣는다.
/// lodeddata는 video관련 data를 불러들이는 거고,
/// timeupdate는 실시간 video time을 catch하는 것임.
/// mousemove와 mouseleave는 video화면 위에 마우스가 있는지,
/// 없는지롤 catch하는 것이다.
/// ''뒷부분은 input이나, click를 했을떄, 작동되는 함수이다.

3. src/client/scss/components/video-play.scss

#videoContainer { 
///JS에 연결할떄뿐만 아니라, scss에서도 #으로 connect가 가능하다.
  width: 100%;
  position: relative; ///control var를 넣기위해 relative로 설정
  video {
    width: 100%;
  }
  .videoControls {
    opacity: 0;
    transition: opacity 0.5s ease-in-out;
    &.showing {
      opacity: 1;
    }
    ///opacity를 0으로 해서 안보이게 해놨다가,
    ///mouses가 들어오면, showing class가 생겨서
    ///opacity가 1로 바뀌어서 보이게 된다.
    
    align-items: center;
    border-radius: 10px;
    position: absolute; ///비디오 화면에 넣기 위해서.
    bottom: 10px;
    width: 95%;
    left: 0;
    right: 0;
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1fr 4fr 1fr auto; ///가로 크기조절
    gap: 10px;
    justify-content: space-between;
    background-color: #0f1117;
    padding: 10px;
    left: 0;
    box-sizing: border-box;
    .videoControls__play {
      display: flex;
      align-items: center;
      justify-content: space-around;
      .videoControls__playBtn {
        margin: 0px 15px;
      }
      .videoControls__time {
        font-size: 12px;
      }
    }
    .videoControls__volume {
      display: flex;
      align-items: center;
      span {
        margin-left: 10px;
        i {
          font-size: 20px;
        }
      }
    }
  }
}

비디오안에 비디오 콘트롤러를 만들어 보는 코딩.
JS와 pug파일을 연결하고, pug파일과 scss를 연결하는
부분은 다시한번 잘 봐둔다.

profile
코딩하는초딩쌤

1개의 댓글

comment-user-thumbnail
2023년 4월 26일

@basket random
비디오에서 비디오 컨트롤러를 생성하기 위해 코딩하는 방법에 대한 자습서에 감사드립니다.

답글 달기