노마드 코더) 모멘텀 클론 코딩

정윤호·2022년 4월 22일
0

클론 코딩

목록 보기
1/1
post-thumbnail

노마드 코더 바닐라 JS로 크롬 앱 만들기 강의를 수강하며 얻은 내용의 정리

먼저 모멘텀이라는 웹 서비스에서 구현할 요소들을 탐색해보자
1) 인사 / 2) 시계 / 3) 명언 / 4) 배경화면 / 5) todo-list / 6) 날씨


HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="css/_style.css">
  <title>Momentum_app</title>
</head>
<body>
  <form action="" id="loginForm" class="hidden">
    <input 
      type="text" 
      id="loginInput"
      required
      maxlength="15"
      placeholder="What's your name?"
    />
    <button>Log In</button>
  </form>
  <h2 id="clock">00:00:00</h2>
  <h1 id="greeting" class="hidden"></h1>
  <form action="" id="todoForm">
    <input 
      type="text"
      required
      placeholder="Write what you need to do today, and press enter!!"
    />
  </form>
  <ul id="todoList">
  </ul>
  <div id="quotes">
    <span></span>
    <span></span>
  </div>
  <div id="weather">
    <span></span>
    <span></span>
  </div>
  <script src="js/_greeting.js"></script>
  <script src="js/_clock.js"></script>
  <script src="js/_quotes.js"></script>
  <script src="js/_background.js"></script>
  <script src="js/_todo.js"></script>
  <script src="js/_weather.js"></script>
</body>
</html>

CSS

.hidden {
  display: none;
}

_greeting.js

const loginForm = document.querySelector("#loginForm");
const loginInput = loginForm.querySelector("input");
const greeting = document.querySelector("#greeting");

const HIDDEN_CLASSNAME = 'hidden';
const USERNAME_KEY = 'username';
const submittedUsername = localStorage.getItem(USERNAME_KEY);

function onloginSubmit(event){
  event.preventDefault();
  const receivedUsername = loginInput.value;
  localStorage.setItem(USERNAME_KEY, receivedUsername);
  paintGreeting(receivedUsername);
  loginForm.classList.add(HIDDEN_CLASSNAME);
}

function paintGreeting(receivedUsername){
  greeting.innerText = `Hello, ${receivedUsername}\nLet's get it!!!`;
  greeting.classList.remove(HIDDEN_CLASSNAME);
}

if (submittedUsername === null){
  loginForm.classList.remove(HIDDEN_CLASSNAME);
  loginForm.addEventListener('submit', onloginSubmit);
} else{
  paintGreeting(submittedUsername);
}
  • 반복되는 문자열의 경우, 대문자 변수에 저장하는게 관습
    Ex) const USERNAME_KEY = 'username';
  • addEventListener : 아규먼트로 event 와 메서드를 받아서, 해당 이벤트가 발생할 때마다 지정한 함수를 실행
  • button 에서 click 이벤트를 감지하기 보다, form 에서 submit 이벤트를 감지
  • JS의 많은 내장함수 중, 많은 경우에 기본적으로 브라우저가 정보를 제공. 단, 패러미터에 자리를 마련해야 하고, 관습적으로 event라는 이름의 변수 이름을 사용
    Ex) event.preventDefault(); : event 오브젝트가 가진 함수 중 하나, 기본 동작들을 멈춤

    기본 동작 : form에 submit을 하면, 자동으로 새로고침을 하고 / link를 클릭하면 해당 페이지로 이동하는 등 디폴트로 설정된 동작

  • localstorage : 유저가 입력한 정보를 save 하고 load 하도록 브라우저가 기억하게 하는 기능
  • .classList : .add.remove 등을 통해, 원하는 지정자에 클래스 id를 붙이고 떼는게 가능

_clock.js

const clock = document.querySelector('h2#clock');

function getClock(){
  const date = new Date();
  const hours = String(date.getHours()).padStart(2, "0");
  const minutes = String(date.getMinutes()).padStart(2, "0");
  const seconds = String(date.getSeconds()).padStart(2, "0");
  clock.innerText = `${hours}:${minutes}:${seconds}`;
}
getClock();
setInterval(getClock, 1000);
  • setInterval : 매 주기마다 함수를 발생시키고 싶을 때 사용. 계속해서 반복된다는 점에서 setTimeout과 차이가 있음. 아규먼트로 실행하고 싶은 메서드와 실행 주기(단위 : ms)를 받음
    Ex) setInterval(sayHi, 1000); : sayHi 라는 함수를 1000ms (1초) 마다 실행
  • Date() : 날짜 정보 등이 담겨 있는 object. .getHours(), getMinutes(), getSeconds() 등을 통해, 현재의 시간 정보도 불러올 수 있음
  • .padStart : 문자열의 길이가 원하는 길이에 미치지 못할 때, 빈 공간을 원하는 문자열로 채워넣을 수 있게 함 / .padEnd는 대상의 끝에 문자열을 채워넣음
    Ex) '15921'.padStart(8, '0') => 00015921
  • 백틱 : 문자열 안에 변수이름을 쓰고 싶을 때, 변수를 ${} 로 감싸야 하는데, 이 문자열은 큰 따옴표나 작은 따옴표가 아닌 백틱으로 감싸야 함

_quotes.js

const quote = document.querySelector("div#quotes span:first-child");
const author = document.querySelector("div#quotes span:last-child");

const quotes = [...
  {
    quote: 'Spread love everywhere you go. Let no one ever come to you without leaving happier.',
    author: 'Mother Teresa',
  }
]
const todaysQuote = quotes[Math.floor(Math.random() * quotes.length)];

quote.innerText = todaysQuote.author;
author.innerText = todaysQuote.quote;
  • Math.floor : 소수점 첫자리에서 버림 / Math.round 는 반올림 / Math.ceil 는 올림
  • Math.random() : 0부터 1사이의 무작위의 소수를 생성

_background.js

const images = [
  "01.jpg",
  "02.jpg",
  "03.jpg",
  "04.jpg",
];

const chosenImage = images[Math.floor(Math.random() * images.length)];
const backgroundImage = document.createElement("img");

backgroundImage.src = `IMG/${chosenImage}`;
document.body.appendChild(backgroundImage);
  • document.createElement() : JS 에서 HTML 요소를 생성
  • .appendChild() : 대상자 안, 가장 아래에 자식 요소를 집어 넣음 / .preppend()의 경우 대상자 안에서 가장 위에 넣음

_todos.js

const todoForm = document.querySelector("form#todoForm");
const toDoInput = todoForm.querySelector("input");
const todoList = document.querySelector("#todoList");

const TODOS_KEY = 'todos';
let todos = [];
const savedTodos = localStorage.getItem(TODOS_KEY);

function handleToDoSubmit(event){
  event.preventDefault();
  const submittedTodo = toDoInput.value;
  toDoInput.value = "";
  const submittedTodoObj = {
    text: submittedTodo,
    id: Date.now(),
  }
  todos.push(submittedTodoObj);
  saveToDos();
  paintToDo(submittedTodoObj);
}

function saveToDos(){
  localStorage.setItem(TODOS_KEY, JSON.stringify(todos));
}

function paintToDo(submittedTodoObj){
  const li = document.createElement("li");
  const listSpan = document.createElement("span");
  const deleteButton = document.createElement("button");
  deleteButton.innerText = "❌";
  li.appendChild(listSpan);
  li.appendChild(deleteButton);
  todoList.appendChild(li);
  deleteButton.addEventListener('click', deleteToDo);
  listSpan.innerText = submittedTodoObj.text;
  li.id = submittedTodoObj.id;
}

function deleteToDo(event){
  const li = event.target.parentElement;
  li.remove();
  todos = todos.filter(item => item.id !== parseInt(li.id));
  saveToDos();
}

if (savedTodos !== null){
  const parsedSavedTodos = JSON.parse(savedTodos);
  todos = parsedSavedTodos;
  todos.forEach(paintToDo);
}

todoForm.addEventListener("submit", handleToDoSubmit);
  • 오늘의 일정을 넣고 빼고, 이를 브라우저가 기억하게 하기 위해서는 todo 입력값들을 배열에 저장하고, localstorage에 JSON string 형식으로 todos 배열을 저장. 삭제 버튼을 누를 때마다, 버튼 누른 li의 id와 동일한 id를 가지는 요소를 todos 배열에서 삭제, 그리고 이를 다시 localstorage에 저장
  • JSON.stringify() : 아규먼트로 받은 object나 array를 JSON string 값으로 변환
  • event.target.parentElement : 이벤트를 발생시킨 지정자의 부모태그를 발견해줌
  • .remove() : 해당 element를 삭제

_weather.js

const API_KEY = 'openweathermapApiKey'; // https://home.openweathermap.org/api_keys 여기서 확인 가능

function onGeoSuccess(position){
  console.log(position);
  const lat = position.coords.latitude;
  const lon = position.coords.longitude;
  const url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric`;
  console.log(url);
  fetch(url)
    .then(response => response.json())
    .then(data => {
      const city = document.querySelector("div#weather span:first-child");
      const weather = document.querySelector("div#weather span:last-child");
      city.innerText = data.name;
      weather.innerText = `${data.weather[0].main} / ${data.main.temp}`;
    });
}

function onGeoFail(){
  alert("sorry, no weather info for you haha!");
}

navigator.geolocation.getCurrentPosition(onGeoSuccess, onGeoFail);
  • navigator : 유저의 정보를 불러오기
  • .geolocation.getCurrentPosition() : 해당 기기가 위치한 위치 정보를 불러오기 위해 사용. 아규먼트로 위치 찾기가 성공 할 때 실행할 함수와 실패할 경우 실행할 함수를 받음.
    패러미터에 위치한 변수 positionconsole.dir 하면, 브라우저가 제공하는 방대한 object 정보 열람 가능
    Ex) position.coords.latitude : 위도 / position.coords.longitude : 경도
  • openweathermap 에서 API 키를 발급, 날씨 API 호출 방법을 확인 =>
    변수로 위도와 경도를 받으면, 날씨 정보를 다른 서버에서 불러올 수 있음

아직 모르는 내용

  • fetch문 :
  • promise문 :
  • .json :
profile
우리 인생 화이팅~

0개의 댓글