과제

요구사항

vanilla js로 할 일 목록 만들기
vanilla js로 내 위치의 날씨 만들기

코드

전체 HTML

<!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="input-box">
            <input type="text" id="userName" />
            <label for="userName">이름을 입력해주세요</label>
          </div>
        </form>
      </section>
      <!-- todo -->
      <section id="todo">
        <form class="todo-box">
          <div class="input-box">
            <input type="text" id="todoInp" />
            <label for="todoInp">할 일을 입력해주세요</label>
          </div>
        </form>
        <ul id="todoList"></ul>
      </section>
    </div>
  </body>
</html>

scriptdefer속성을 주어, 스크립트의 다운로드와 함께 html렌더 중지를 하지 않고 렌더가 완료되고 스크립트의 실행을 시켜주었다

날씨

위치 기반의 날씨를 렌더링 하려면 두 가지의 문제가 있었다

  • 내 위치를 알아내야 한다(가져와야한다)
  • 해당 위치의 날씨 정보를 알아내야 한다(가져와야한다)

첫번째 문제는 Web apinavigator(의 geolocation)를 활용하면 된다

Web api란 자바스크립트에 내장된 모델은 아니지만, 우리가 현재 자바스크립트를 실행시키는 웹에서 제공되는 api이다

Navigator 인터페이스는 사용자 에이전트의 상태와 신원 정보를 나타내며, 스크립트로 해당 정보를 질의할 때와 애플리케이션을 특정 활동에 등록할 때 사용합니다.
Navigator 객체는 window.navigator 읽기 전용 속성으로 접근할 수 있습니다.
Navigator.geolocation 읽기 전용 속성은 웹에서 장치의 위치를 알아낼 때 사용할 수 있는 Geolocation 객체를 반환합니다. 웹 사이트나 웹 앱은 위치정보를 사용해 결과 화면을 맞춤 설정할 수 있습니다.
[출처] MDN(Navigator-Web API)

코드에서 우선 해당브라우저에서 API를 사용할 수 있는지 분기처리하고, 사용할 수 있다면 open api를 활용해서 기능을 구현해주도록 한다

또한 open api 데이터를 가져올 때 생길 에러상황도 구현해준다

// weather
const KEY = "cd9fca71fbee843c7a38d104afaf8bf8";
const $sectionWeather = document.getElementById("weather");

const getWeather = async ({ latitude, longitude }) => {
  try {
    const res = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${KEY}&units=metric`
    );
    const json = await res.json();
    const { weather, main } = json;

    const $div = document.createElement("div");
    $div.classList.add("wrap-weather");
    const $span = document.createElement("span");
    const $img = document.createElement("img");
    $span.textContent = main.temp + "°C";
    $img.src = `http://openweathermap.org/img/wn/${weather[0].icon}@2x.png`;

    $div.appendChild($img);
    $div.appendChild($span);

    $sectionWeather.appendChild($div);
  } catch (error) {
    const $div = document.createElement("div");
    $div.classList.add("wrap-weather");
    const $span = document.createElement("span");
    $span.textContent = "fail to load weahter";
    $div.appendChild($span);
    $sectionWeather.appendChild($div);
  }
};
if ("geolocation" in navigator) {
  console.log("위치정보 사용 가능");

  navigator.geolocation.getCurrentPosition((position) => {
    const { latitude, longitude } = position.coords;
    getWeather({ latitude, longitude });
  });
} else {
  console.log("위치정보 사용 불가능");
}

openweathermap API KEY는 현재 inactivate해놓았습니다

할 일 목록

투두리스트의 경우엔, form으로 사용자의 입력값을 받아서 todos라는 배열에 투두를 푸쉬하고, 해당 배열을 렌더링해주는 방식으로 구현했다

입력을 마치고 배열에 투두가 잘 들어갔다면, 입력창을 초기화하고 포커싱을 떼주는 기능까지 구현했다

삭제의 경우, 투두에다가 id를 삽입해두었다가 해당 id를 기준으로 배열에서 filter해주는 방식을 사용했다

삭제가 된 todos라는 배열을 다시 렌더링 해주면 삭제기능은 끝이다

form의 경우 default로 행동하는 새로고침을 막기위해 이벤트의preventDefault를 활용했다

// todo
const $todoList = document.getElementById("todoList");
const $todoForm = document.querySelector(".todo-box");

let todos = [];

$todoForm.addEventListener("submit", (e) => {
  e.preventDefault();
  const todo = e.target[0].value;
  if (!todo) return;

  todos.push({
    id: todos.length,
    desc: todo,
  });

  renderTodos();

  e.target[0].value = "";
  document.getElementById("todoInp").blur();
});

function renderTodos() {
  $todoList.innerHTML = "";
  todos.forEach((todo) => {
    const $li = document.createElement("li");
    const $inp = document.createElement("input");
    const $span = document.createElement("span");
    const $btn = document.createElement("button");

    $li.id = todo.id;
    $li.classList.add("todo");

    $inp.name = todo.id;
    $inp.id = todo.id;
    $inp.type = "checkbox";

    $span.textContent = todo.desc;
    $span.htmlFor = todo.id;

    $btn.classList.add("delete");
    $btn.textContent = "삭제";

    $li.appendChild($inp);
    $li.appendChild($span);
    $li.appendChild($btn);

    $btn.addEventListener("click", (e) => {
      deleteTodo(e.target.parentNode.id);
    });

    $todoList.appendChild($li);
  });
}
function deleteTodo(id) {
  todos = todos.filter((todo) => todo.id != id);
  renderTodos();
}

결과





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

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

0개의 댓글