과제

요구사항

과제의 요구사항은 총 3개로, 하나의 페이지에 구현하는 것이다
추가 요구사항은 목요일 과제로 진행될 예정이다

  • vanilla js로 배경이미지 랜덤 변경
  • vanilla js로 인사 만들기
  • vanilla js로 시계 만들기

코드

HTML

앱 전체를 div id=app으로 감싸준 뒤, 구현해야할 기능별로 section을 나눠주었다
사용자의 이름을 입력받을 섹션에는 기본적으로 hide라는 class를 주어 숨김처리하고 있다(추후에 js로 컨트롤하여 이 클래스를 제거해준다)

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Hello World?</title>
    <link rel="stylesheet" href="./style/reset.css" />
    <link rel="stylesheet" href="./js-assignment-css.css" />
    <script defer src="./js-assignment-js.js"></script>
  </head>
  <body>
    <div id="app">
      <!-- weather -->
      <section id="weather"></section>
      <!-- clock -->
      <section id="clock"></section>
      <!-- greeting -->
      <section id="greeting" class="hide">
        <form class="login-box">
          <div class="user-box">
            <input type="text" id="userName" />
            <label for="userName">이름을 입력해주세요</label>
          </div>
        </form>
      </section>
      <!-- todo -->
      <section id="todo">
        <form>
          <!-- <input type="text" name="" id="" /> -->
        </form>
      </section>
    </div>
  </body>
</html>

CSS

전에는 background-image를 쓰지않고 이미지태그 하나, 백그라운드 어두운처리용 div를 썼었는데 그러지 않아도 어둡게 처리할 수 있다

background-image: linear-gradient(rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.75)), url("IMG_PATH")

Javascript

스크립트는 IIFE로 즉시실행을 해준다(없어도 실행은 되지만 전역변수의 사용을 피하기위해 사용하였다)

(() => {
  console.log("IIFE");
  ...
})()

랜덤 배경화면은 준비된 이미지들의 PATH들을 담은 배열과 Math.random()을 활용하여 background스타일의 url을 갈아끼워주는 방식으로 구현했다

// random background
const DEFAULT_PATH = "./assets/";
const imgPaths = [
    "bg-bicycle.jpeg",
    "bg-bunny.jpeg",
    "bg-forest.jpeg",
    "bg-japan.jpeg",
    "bg-ocean.jpg",
    "bg-wall.jpeg",
];
const App = document.getElementById("app");
App.style.backgroundImage = `linear-gradient(rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.75)), url(${DEFAULT_PATH + imgPaths[Math.floor(Math.random() * imgPaths.length)]
})`;

인사의 경우, 로컬스토리지를 활용해 값이 있는 경우와 없는 경우에 렌더링되어야 하는 요소가 다르다
이를 구현하기위해 렌더링을 해주는 함수는 밖으로 빼주었다

분리된 함수를 통해, 값을 가져왔을 때(로컬스토리지로부터) 있다면 인사를 렌더링하고 없다면 formhide클래스를 제거하여 유저로부터 이름을 받는다

// greeting
let userName = localStorage.getItem("userName");
const $loginForm = document.querySelector(".login-box");

const showGreeting = () => {
  $loginForm.remove();
  userName = localStorage.getItem("userName");
  const $sectionGreeting = document.getElementById("greeting");
  const $h1 = document.createElement("h1");
  $h1.textContent = userName + "님 안녕하세요";
  $sectionGreeting.appendChild($h1);
};

if (userName) showGreeting();
else {
  document.getElementById("greeting").classList.remove("hide");
  $loginForm.addEventListener("submit", (e) => {
    e.preventDefault();
    const userName = document.getElementById("userName").value.trim();
    if (userName) {
      document.getElementById("userName").value = "";
      // blur(): Remove focus from a text input
      document.getElementById("userName").blur();
      localStorage.setItem("userName", userName);
      showGreeting();
    }
  });
}

시계의 경우 핵심은 1초마다 현재시간을 렌더링해야 하는것이 필수였다
이를 위해 시간을 지정하면 콜백함수를 실행시키는 setInterval를 활용했다
약간의 문제점은 setInterval은 지정한 시간 이후부터 실행이 되기에 약간의 딜레이가 생긴다
이를 해결하기 위해 시간을 출력하는 함수를 분리하고, setInterval이전에 showTime을 한번만 실행해주면 조금 더 부드럽게 출력이 된다

// clock
const $sectionClock = document.getElementById("clock");
const $h2 = document.createElement("h2");
const showTime = () => {
  const now = new Date();

  const hours = now.getHours();
  const minutes = now.getMinutes();
  const seconds = now.getSeconds();
  const AMPM = hours > 12 ? "PM" : "AM";

  const addZero = (num) => {
    let result = String(num);
    return result.length === 1 ? "0" + result : result;
  };

  $h2.textContent = `${AMPM} ${addZero(hours)} : ${addZero(
    minutes
  )} : ${addZero(seconds)}`;

  $sectionClock.appendChild($h2);
};
showTime();
setInterval(showTime, 1000);

결과

  • 새로고침을 할 때마다 무작위 배경화면이 렌더링 된다
  • setInterval을 활용해 1000ms의 시간마다 현재시간을 보여준다
  • localStoargeuserName이라는 key를 가진 value가 없다면, formhide라는 class를 제거하여 폼을 보여준 뒤 입력받을 수 있도록 해주고, 해당 value가 있다면 인사말을 남긴다



본 후기는 유데미-스나이퍼팩토리 10주 완성 프로젝트캠프 학습 일지 후기로 작성 되었습니다.

profile
😂그냥 직진하는 (예비)개발자

0개의 댓글