[TIL] 211210

dev·2021년 12ė›” 10ėž
0

TIL

ëŠĐ록 ëģīęļ°
114/204
post-thumbnail

📝 ė˜Ī늘 한 ęēƒ

  1. video player - webpack ė„Īė • / playBtn / muteBtn / volume bar

📚 ë°°ėšī ęēƒ

video player

1. webpack ė„Īė •

1) entry / output

video playerëĨž ëŠĻ든 페ėīė§€ė—ė„œ 로드할 í•„ėš”ëŠ” ė—†ë‹Ī. video가 ėžˆëŠ” 페ėī맀뗐 ë“Īė–īę°”ė„ 때만 로드되도록 하ęļ° ėœ„í•ī video player ėžë°”ėŠĪ큎ëĶ―íŠļ íŒŒėžė„ í•īë‹đ íŒŒėž ė•ˆė—ë§Œ 폎í•Ļė‹œėžœėĪ„ ęēƒėīë‹Ī. ėīëĨž ėœ„í•ī 멇 氀맀 ęģžė •ė„ ęą°ėģė•ž 한ë‹Ī.

í˜„ėžŽ entry point는 하나ëŋėīë‹Ī. videoPlayer.js íŒŒėžė„ 만든 후 ė˜ĪëļŒė íŠļëĨž ėīėšĐí•ī ėķ”ę°€í•œë‹Ī.
output 또한 í˜„ėžŽëŠ” ëŽīėĄ°ęąī main.js íŒŒėžė— ėƒė„ąë˜ëŊ€ëĄœ ėīęēƒë„ webpackė—ė„œ ė§€ė›í•˜ëŠ” ë°Đė‹ė„ ėīėšĐí•ī ėˆ˜ė •í•œë‹Ī.

// webpack.config.json
const path = require("path");

module.exports = {
  entry: {
    main: "src/client/js/main.js",
    videoPlayer: "src/client/js/videoPlayer.js", // ėķ”ę°€ ❗
  },
  output: {
    filename: "js/[name].js", // ėˆ˜ė • ❗
    path: path.resolve(__dirname, "assets"),
  }
};

watch 페ėī맀뗐 ë“Īė–īę°”ė„ 때 video player가 로드될 눘 ėžˆë„ëĄ watch.pug íŒŒėžėī videoPlayer.jsëĨž 가ė ļė™€ė•ž 한ë‹Ī. ė͉, watch.pug íŒŒėžė— script 태ę·ļëĨž ë„Ģė–īė•ž 한ë‹Ī.
ėīëĨž ėœ„í•ī base.pug íŒŒėžė— block scriptsëĨž ėķ”ę°€í•œ 후, watch.pug íŒŒėžė—ė„œ scriptëĨž ėķ”가할 눘 ėžˆë‹Ī.

//- base.pug

block scripts
//- watch.pug

block scripts
  script(src="/static/js/videoPlayer.js")

ðŸ’Ą ėī때 ęļ°ėĄī뗐 base.pug뗐 ėžˆë˜ script(src="/static/js/main.js")ëĨž ė‚­ė œí•ī도 ė—ëŸŽëŠ” ë°œėƒí•˜ė§€ ė•ŠëŠ”ë‹Ī.

main.js íŒŒėžė€ client íī더 ė•ˆė˜ styles.scss íŒŒėžė„ import 하는 íŒŒėžëĄœėĻ main.js íŒŒėž ė•ˆė˜ ė―”ë“œę°€ ė‹Īí–‰ë˜ëŠ”ė§€ 확ėļ하ęļ° ėœ„í•œ ëŠĐė ėœžëĄœ console.log()뙀 í•Ļęŧ˜ base.pug íŒŒėžė—ė„œ 가ė ļė™”ë˜ íŒŒėžėīë‹Ī.

ë”°ëžė„œ, ėīëĨž base.pug íŒŒėžė—ė„œ ė‚­ė œí•˜ë”ëžë„ (client íī더 ė•ˆė˜ styles.scss íŒŒėžė„ import 하는) main.js íŒŒėžë§Œ ėĄīėžŽí•œë‹ĪëĐī, webpackė€ ėīëĨž 확ėļ하ęģ  client뗐 ėĄīėžŽí•˜ëŠ” ëģ€í™˜ë“Īė„ assets뗐 바ęŋ”ėĪ„ ęēƒėīë‹Ī.

ė •ëĶŽí•˜ėžëĐī, output ėŠĪ큎ëĶ―íŠļ는 cssëĨž 가ė ļė˜Īė§€ ė•Šęģ , input ėŠĪ큎ëĶ―íŠļ만ėī cssëĨž 가ė ļė˜Īëа, ėī는 webpackėœžëĄœ ęĩŽëķ„된ë‹Ī.


2. video player 만ë“Īęļ°

MDN - HTMLMediaElement ė°ļęģ 
HTMLVideoElement는 HTMLMediaElementëĨž ėƒė†í•œë‹Ī. ë”°ëžė„œ, video 태ę·ļ는 HTMLMediaElementė˜ ė†ė„ąęģž ëĐ”ė„œë“œëĨž ė‚ŽėšĐ할 눘 ėžˆë‹Ī.

1) HTML ë§ˆíŽė—…

watch.pug íŒŒėžė—ė„œ video playerëĨž 만든ë‹Ī.

//- watch.pug

block content
  video(src="/" + video.fileUrl, width="800", controls)
  div
    button#playBtn Play
    button#muteBtn Mute
    span#time 00:00/00:00
    input(type="range", step="0.1", min="0", max="1")#volume

각 ėš”ė†Œë“Īė„ videoPlayer.js íŒŒėžëĄœ 가ė ļė˜Ļë‹Ī.

// videoPlayer.js
const video = document.querySelector("video");
const playBtn = document.getElementById("plyBtn");
const muteBtn = document.getElementById("muteBtn");
const time = document.getElementById("time");
const volumeRange = document.getElementById("volume");

ëģžëĨĻ bar가 ëŊļëĶŽ ėž‘ė„ąí•īë†“ė€ input ė„Īė • 값 때ëŽļ뗐 ė›í•˜ëŠ” 대로 ëģīėīė§€ ė•Šė•„ forms.scssëĨž ėˆ˜ė •í–ˆë‹Ī.

// forms.scss
input:not(input[type="range"]) { ... }

2) playBtn

video.paused는 boolean ę°’ė„ return 한ë‹Ī.
ėīëĨž ėīėšĐí•ī video가 ėžŽėƒ ėĪ‘ėļė§€ 확ėļ할 눘 ėžˆë‹Ī.

ėžŽėƒ ė—Žëķ€ė— 따띾 button ė•ˆė˜ text도 바ęūļ도록 한ë‹Ī.

// videoPlayer.js
const handlePlayBtnClick = (e) => {
  if (video.paused) {
    video.play();
  } else {
    video.pause();
  }
  playBtn.innerText = video.paused ? "Play" : "Pause";
};

playBtn.addEventListener("click", handlePlayBtnClick);

3) muteBtn

(1) mute / unmute

video.muted는 boolean ę°’ė„ return 한ë‹Ī.
video.pasued뙀 닮ëĶŽ ė―ęģ  ė“°ëŠ” ęēƒėī ëŠĻ두 가ëŠĨ하ë‹Ī.
ė͉, ėŒė†Œęą° ėƒíƒœėļė§€ 확ėļ할 ėˆ˜ë„ ėžˆęģ , ėŒė†Œęą° ėƒíƒœëĄœ 만ë“Ī ėˆ˜ë„ ėžˆë‹Ī.

ėŒė†Œęą° ė—Žëķ€ė— 따띾 button ė•ˆė˜ text도 바ęūļ도록 한ë‹Ī.

// videoPlayer.js
const handleMute = () => {
  if (video.muted) {
    video.muted = false;
  } else {
    video.muted = true;
  }
  muteBtn.innerText = video.muted ? "Unmute" : "Mute";
};

muteBtn.addEventListener("click", handleMute);

(2) video.volumeęģž input[type="range"] ė—°ęē°

ė‹Ī렜 ëģžëĨĻęģž ëģžëĨĻ ë°”ëĨž ė—°ë™í•īė•ž 한ë‹Ī.

ðŸ’Ą ëģžëĨĻ ë°”ė˜ 폎ėļ터ëĨž ė›€ė§ėž 때마ë‹Ī ëģžëĨĻė˜ 큎ęļ°ę°€ ëģ€í•˜ë„록

ėŒė†Œęą° ëē„íŠžė„ 누ëĨīëĐī ëģžëĨĻ ë°”ė˜ 폎ėļ터가 ë§Ļ ė™žėŠ―ėœžëĄœ ė˜Ī도록 만ë“Īė–īė•ž 한ë‹Ī.
ė͉, video.volumeė˜ 값ęģž input[type="range"]ė˜ valueëĨž ė—°ęē°í•īė•ž 한ë‹Ī.

ėīëĨž ėœ„í•ī input ėīëēĪíŠļëĨž ėīėšĐ할 눘 ėžˆë‹Ī.
volumeRange input뗐 input ėīëēĪíŠļëĨž 등록í•Ļ뗐 따띾 inputė˜ value 값ėī ëģ€í•  때마ë‹Ī handleVolumeChange ėīëēĪíŠļ í•ļë“Ī럮 í•Ļėˆ˜ę°€ ė‹Ī행된ë‹Ī.

// videoPlayer.js
const handleVolumeChange = (event) => {
  const { target: { value } } = event;
  video.volume = value;
};

volumeRange.addEventListener("input", handleVolumeChange);

ėī렜 ëģžëĨĻ ë°”ė˜ 폎ėļ터ëĨž ėĒŒėš°ëĄœ ė›€ė§ėž 때마ë‹Ī videoė˜ ė‹Ī렜 ëģžëĨĻėī ëģ€í•˜ëŠ” ęēƒė„ 확ėļ할 눘 ėžˆë‹Ī.

ðŸ’Ą ėŒė†Œęą° ėƒíƒœėž 때, ëģžëĨĻ ë°” 뛀링ėīëĐī, ę·ļ뗐 맞ėķ° ëģžëĨĻ íŽęļ°ę°€ ëģ€í•˜ë„록

ę·ļ럮나, ėŒė†Œęą° ëē„íŠžė„ ëĻžė € 눌럮 ėŒė†Œęą° ėƒíƒœėž 때는 ëģžëĨĻ ë°”ëĨž ė›€ė§ė—Žë„ ę·ļ대로 ėŒė†Œęą° ėƒíƒœėīë‹Ī.

volumeRangeė˜ value 값ęģž video.volumeė˜ 값ėī ëŠĻ두 ëģ€í•˜ęļī í•˜ė§€ë§Œ, video.muted가 true ę°’ė„ 氀맀ęļ° ë•ŒëŽļ뗐 ęģ„ė† ėŒė†Œęą° ėƒíƒœę°€ ėœ ė§€ë˜ëŠ” ęēƒėīë‹Ī.

ë”°ëžė„œ, handleVolumeChange í•Ļ눘 ė•ˆė—ė„œ video.muted가 true 값ėļ ęē―뚰ëĨž ėķ”ę°€ëĄœ ë‹ĪëĪ„ėĪ˜ė•ž 한ë‹Ī.

const handleVolumeChange = (event) = {
  const { target: { value } } = evenvt;
  if (video.muted) {
    video.muted = false;
    muteBtn.innerText: "Mute";
  }
  video.volume = value;
};

ėī렜 ėŒė†Œęą° ėƒíƒœėļ ęē―ėš°ė—ë„ ëģžëĨĻ ë°”ëĨž 뛀링ėīëĐī ė›í•˜ëŠ” 대로 ëģžëĨĻėī ėĄ°ė •ë˜ëŠ” ęēƒė„ 확ėļ할 눘 ėžˆë‹Ī.

ðŸ’Ą ėŒė†Œęą° ėƒíƒœėž 때, ėŒė†Œęą° ëē„튞 ë‹Īė‹œ 한ëēˆ ëˆ„ëĨīëĐī, ė†ŒëĶŽę°€ ëŒė•„ė˜Ī도록

ę·ļ럮나, ėŒė†Œęą° ėƒíƒœė—ė„œ ėŒė†Œęą° ëē„íŠžė„ ë‹Īė‹œ 눌럮 ëģžëĨĻė„ ëŒė•„ė˜ĪęēŒ ë§Œë“Īė–ī도, ëģžëĨĻ ë°”ëŠ” ėŒė†Œęą° ėīė „ė˜ ėƒíƒœëĄœ ëŒė•„ė˜Īė§€ ė•Šęģ  ę·ļ대로 ë§Ļ ė™žėŠ―ė— ë‚Ļė•„ ėžˆë‹Ī.

video.volumeė„ ęļ°ė–ĩ하ęģ  ė—…ë°ėīíŠļí•˜ė—Ž ėŒė†Œęą° ė—Žëķ€ė— 따띾 inputė˜ value 값ėī ë‹Žëžė§€ë„ëĄ 한ë‹Ī.

// videoPlayer.js
const volumeValue = 0.3;
video.volume = volumeValue;

const handleMute = () => {
  if (video.muted) {
    video.muted = false;
  } else {
    video.muted = true;
  }
  muteBtn.innerText = video.muted ? "Mute" : "Unmute";
  volumeRange.value = video.muted ? 0 : volumeValue; // ėŒė†Œęą° ėƒíƒœ í•īė œë˜ëĐī ėīė „ ëģžëĨĻėī ë‹Īė‹œ ëŒė•„ė˜ī
};

const handleVolumeChange = (event) => {
  const { target: { value } } = event;
  if (video.muted) {
    video.muted = false;
    muteBtn.innerText = "Mute";
  }
  volumeValue = value;
  video.volume = volumeValue;
};

âœĻ ë‚īėž 할 ęēƒ

  1. video player
profile
dev log

0ę°œė˜ 댓ęļ€