들어가기
JS를 이용해서, watch.pug에 비디오 controler를 만들어본다.
play, mute, fullScreen등등.
JS를 다시 복습하고 익혀 보도록 한다.
---------부분은 참고만 하라고 남겨둠.
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 →
--------------------------------------------------------
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를 했을떄, 작동되는 함수이다.
#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를 연결하는
부분은 다시한번 잘 봐둔다.
@basket random
비디오에서 비디오 컨트롤러를 생성하기 위해 코딩하는 방법에 대한 자습서에 감사드립니다.