[TIL] 211230

Lee Syong·2021년 12ė›” 30ėž
0

TIL

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

📝 ė˜Ī늘 한 ęēƒ

  1. ëģĩėŠĩ - VIDEO PLAYER

📚 ë°°ėšī ęēƒ (ëģĩėŠĩ)

8. VIDEO PLAYER

  • [TIL] 211211
    • ėŒė†Œęą° & ëģžëĨĻ ėˆ˜ė • (ėķ”ę°€)
    • input[type="range"] CSS ėŠĪ타ėžë§ - 타ėž„띞ėļ & ëģžëĨĻ 바 (ėķ”ę°€)

ðŸ’Ą ėŒė†Œęą° & ëģžëĨĻ ėˆ˜ė •

click / keydown / input / change / volumechange

const videoContainer = document.querySelector("video-container");
const video = document.querySelector("video");
const videoPlayer = document.querySelector(".video-player");
const playBtn = document.querySelector(".video-player__play");
const muteBtn = document.querySelector(".video-player__mute");
const volumeRange = document.querySelector(".video-player__volume");
const time = document.querySelector(".video-player__time");
const currentTime = document.querySelector(".video-player__currentTime");
const totalTime = document.querySelector(".video-player__totalTime");
const timeline = document.querySelector(".video-player__timeline");
const fullScreen = document.querySelector(".video-player__fullScreen");

let volumeValue = 0.3;
video.volume = volumeValue;

const handlePlayBtnClick = () => {
  if (video.paused) {
    video.play();
  } else {
    video.pause();
  }
  playBtn.innerHTML = video.paused
    ? "<i class='fas fa-play'></i>"
    : "<i class='fas fa-pause'></i>";
};

const handleMuteBtnClick = () => {
  if (video.muted) {
    video.muted = false;
    video.volume = volumeValue;
  } else {
    video.muted = true;
    video.volume = 0;
  }
};

const handleVolumeChange = () => {
  volumeRange.value = video.volume;
  if (video.muted) {
    muteBtn.innerHTML = "<i class='fas fa-volume-mute'></i>";
  } else {
    muteBtn.innerHTML = "<i class='fas fa-volume-up'></i>";
  }
};

const handleVolumeValueInput = () => {
  if (volumeRange.value === "0") {
    video.muted = true;
    video.volume = 0;
  } else {
    video.muted = false;
    video.volume = volumeRange.value;
  }
};

const handleVolumeValueChange = () => {
  volumeValue = video.volume === 0 ? volumeValue : video.volume;
};

const formatTime = (seconds) => {
  const min = String(Math.floor(seconds / 60));
  const second = String(Math.floor(seconds % 60));
  return `${min.padStart(2, "0")}:${second.padStart(2, "0")}`;
};

const handleLoadedMetadata = () => {
  currentTime.textContent = formatTime(video.currentTime);
  totalTime.textContent = formatTime(video.duration);
  timeline.max = video.duration;
};

const handleTimelineChange = () => {
  video.currentTime = timeline.value;
};

const handleCurrentTimeUpdate = () => {
  currentTime.textContent = formatTime(video.currentTime);
  timeline.value = String(Math.floor(video.currentTime));
};

const handleFullScreenClick = () => {
  if (document.fullscreenElement) {
    document.exitFullscreen();
  } else {
    video.requestFullscreen();
  }
  fullScreen.innerHTML = document.fullscreenElement
    ? "<i class='fas fa-compress'></i>"
    : "<i class='fas fa-expand'></i>";
};

const handleVideoEnded = () => {
  video.currentTime = 0;
  playBtn.innerHTML = "<i class='fas fa-play'></i>";
};

const handleKeyDown = (event) => {
  const { key } = event;
  switch (key) {
    case " ":
      event.preventDefault();
      handlePlayBtnClick();
      break;
    case "Enter":
      event.preventDefault();
      handleFullScreenClick();
      break;
    case "ArrowRight":
      event.preventDefault();
      video.currentTime += 1;
      break;
    case "ArrowLeft":
      event.preventDefault();
      video.currentTime -= 1;
      break;
    case "m":
      event.preventDefault();
      handleMuteBtnClick();
      handleVolumeChange();
      break;
    case "ArrowUp":
      event.preventDefault();
      if (video.volume === 1) {
        return;
      }
      video.volume = (video.volume + 0.1).toFixed(1);
      volumeValue = video.volume;
      video.muted = false;
      break;
    case "ArrowDown":
      event.preventDefault();
      if (video.volume === 0) {
        return;
      }
      video.volume = (video.volume - 0.1).toFixed(1);
      volumeValue = video.volume === 0 ? volumeValue : video.volume;
      if (video.volume === 0) {
        video.muted = true;
      }
      break;
  }
};

playBtn.addEventListener("click", handlePlayBtnClick);
muteBtn.addEventListener("click", handleMuteBtnClick);
video.addEventListener("volumechange", handleVolumeChange);
volumeRange.addEventListener("input", handleVolumeValueInput);
volumeRange.addEventListener("change", handleVolumeValueChange);
video.addEventListener("loadedmetadata", handleLoadedMetadata);
timeline.addEventListener("input", handleTimelineChange);
video.addEventListener("timeupdate", handleCurrentTimeUpdate);
fullScreen.addEventListener("click", handleFullScreenClick);
video.addEventListener("ended", handleVideoEnded);
window.addEventListener("keydown", handleKeyDown);

ðŸ’Ą input[type="range"] CSS ėŠĪ타ėžë§ (ėķ”ę°€)

input 타ėž… range ėŠĪ타ėž ėˆ˜ė •í•˜ęļ°_ėŧĪėŠĪ텀 ėŠĪ타ėž / input rangeė— ėŠĪ타ėž ėķ”ę°€í•˜ęļ° ė°ļęģ 

타ėž„띞ėļ & ëģžëĨĻ 바 ėŠĪ타ėžė„ ėˆ˜ė •í–ˆë‹Ī.
linear-gradient()ëĨž ėīėšĐí•ī ė§„í–‰ ėƒí™Đė— 따띾 ėƒ‰ęđ”ė„ 닮ëĶŽ 표ė‹œí–ˆë‹Ī.

// videoPlayer.scss

.video-player {
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 90%;
  padding: 1rem 0;
  position: absolute;
  left: 50%;
  bottom: 0;
  transform: translateX(-50%);
}

// timeline (videoPlayer.js ė°ļęģ )

input[type="range"] {
  -webkit-appearance: none;
  width: 97%;
  height: 0.3rem;
  border-radius: $border-radius-lg;
  background: $color-white;
  margin: 0 auto;
  cursor: pointer;
}

input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 0.8rem;
  height: 0.8rem;
  border-radius: 50%;
  background: $color-light-blue;
  cursor: pointer;
}

// controls

.video-player__controls {
  display: flex;
  justify-content: space-between;
  width: 97%;
  margin: 0 auto;
  margin-top: 1rem;
  font-size: $font-small;
  .video-player__play button,
  .video-player__mute button,
  .video-player__fullScreen button {
    width: 3rem;
    font-size: $font-medium;
    color: $color-dark-white;
  }
}

.video-player__left-controls {
  display: flex;
  align-items: center;
  .video-player__volume {
    width: 4rem;
    margin: 0 1rem;
  }
  .video-player__time {
    margin: 0 1rem;
  }
}
// videoPlayer.js
const PROGRESSED_COLOR = "rgb(168, 218, 220)"; // $color-light-blue
const LEFT_COLOR = "rgba(241, 250, 238, 0.7)"; // $color-white

let volumeValue = 0.3;
video.volume = volumeValue;
volumeRange.style.background = `linear-gradient(to right, ${PROGRESSED_COLOR} 0%, ${PROGRESSED_COLOR} 30%, ${LEFT_COLOR} 30%, ${LEFT_COLOR} 100%)`;

const setTimelineColor = (inputRangeName) => {
  const { value } = inputRangeName;
  const gradientValue = (100 / +inputRangeName.max) * +value;
  inputRangeName.style.background = `linear-gradient(to right, ${PROGRESSED_COLOR} 0%, ${PROGRESSED_COLOR} ${gradientValue}%, ${LEFT_COLOR} ${gradientValue}%, ${LEFT_COLOR} 100%)`;
};

const handleTimelineValueInput = () => {
  video.currentTime = timeline.value;
  setTimelineColor(timeline);
};

const handleCurrentTimeUpdate = () => {
  currentTime.textContent = formatTime(video.currentTime);
  timeline.value = String(Math.floor(video.currentTime));
  setTimelineColor(timeline);
};

const handleKeyDown = (event) => {
  const { key } = event;
  switch (key) {
    // ėĪ‘ëžĩ
    case "ArrowRight":
      event.preventDefault();
      video.currentTime += 1;
      setTimelineColor(timeline);
      break;
    case "ArrowLeft":
      event.preventDefault();
      video.currentTime -= 1;
      setTimelineColor(timeline);
      break;
    case "m":
      event.preventDefault();
      handleMuteBtnClick();
      handleVolumeChange();
      break;
    case "ArrowUp":
      // ėĪ‘ëžĩ
      setTimelineColor(volumeRange);
      break;
    case "ArrowDown":
      // ėĪ‘ëžĩ
      setTimelineColor(volumeRange);
      break;
  }
};

timeline.addEventListener("input", handleTimelineValueInput);
video.addEventListener("timeupdate", handleCurrentTimeUpdate);
window.addEventListener("keydown", handleKeyDown);

ėˆ˜ė • 필ėš”í•Ļ


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

  1. ëģĩėŠĩ ęģ„ė†í•˜ęļ° - VIDEO PLAYER
profile
ëŠĨ동ė ėœžëĄœ ė‚īėž, 행ëģĩ하ęēŒðŸ˜

0개ė˜ 댓ęļ€