24/4/9 바닐라 자바스트립트

2024. 4. 9. 23:01카테고리 없음

코딩테스트 갔다가 부딪힌 바닐라 자바스크립트 

난 참패 했다. react랑 next만 들여다 보고 바닐라 자바스크립트를 소홀히 했기 때문에 일어난 대참사였다.

애초에 작년 10월부터 코딩을 시작했으면서 뭔 자신감으로 바닐라를 무시한건지... 븅딱이다.

html요소를 끌어와야 되는데 document.querySelector 나  document.getElementById 의 document가

생각이 안나서 15분동안 html.getElementById 이었나??? 아닌뎅? body.queryselector인가? 이러면서
땀만 흘리고 있었다. 반성의 의미로 시작된 바닐라 조지기 프로젝트 출발한다.


노마드 코더님의 자바스크립트로 크롬앱만들기 클론코딩

 

<index.html> 

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="css/style.css" />        //css 파일 불러오기
    <title>바닐라 자바스크립트</title>
  </head>

  <body>
    <form class="hidden" id="loginForm">    //hidden 이라는 class에 display : none을 주어
      <input                                                      //기본적으로 보이지 않는 form 태그
        required                                              //required 를 주어서 input태그에 value가 반드시 있어야 됨
        maxlength="15"                                  //최대 길이값을 설정
        type="text"                                          //이건 뭐 안줘도 된다. type으로 input의 종류가 달라진다.
        placeholder="넌 이름이 뭐니?"            //value가 없을때 보여지는 안내문 정도?
      />
      <button>로그인</button>
    </form>
    <h1 id="greet" class="hidden"></h1>
    <h2 id="clock"></h2>
    <div id="weather">
      <span></span>
      <span></span>
    </div>

    <a href="about.html">어바웃으로</a>   //html간의 이동방식 주로 앵커태그를 이용
    <form id="todoform"><input type="text" placeholder="작성하세용" /></form>
    <ul id="todoList"></ul>
    <div id="quote">
      <span></span>
      <span></span>
    </div>
    <script src="./js/app.js"></script>
    <script src="./js/clock.js"></script>
    <script src="./js/quote.js"></script>
    <script src="./js/backGround.js"></script>
    <script src="./js/todo.js"></script>
    <script src="./js/weather.js"></script>
  </body>
</html>

 

<app.js>로그인의 기본적인 동작원리를 다룬 js

const loginForm = document.querySelector("#loginForm");     //tag를 가져오는 방식 쿼리셀렉터 이다
const loginInput = document.querySelector("#loginForm input");  //태그에 id이름으로 끌어올려면 #샵을
const greet = document.querySelector("#greet");                           //클래스로 가져올려면 .온점을 사용하고
const link = document.querySelector("a");                                    //해당네임을 가져온다.
const HIDDEN_CLASS = "hidden";
const USER_NAME = "username";                           //휴먼에러를 줄이기 위한 상수의 변수 선언

const onLoginSubmit = function (tomato) {             //로그인은 기본적으로 form태그를 이용한다.
  tomato.preventDefault();                                   //폼태그는 submit속성의 버튼 클릭시 자동새로고침된다.
  loginForm.classList.add(HIDDEN_CLASS);     //preventDefault 로 새로고침을 막는다.
  const username = loginInput.value;                            //위에서 끌어온 로그인폼에 classList.add를 통해 
  console.log(username);                                   //특정 클래스명을 추가해주고 인풋의 value를 따로 담아둔다.
  localStorage.setItem(USER_NAME, username);    //새로고침시 날아가버리는 data를 보관하기 위한
  faintGreet(username);                                           //로컬스토리지
};                                                                  //faint는 말고 paint인데 귀찮아서 놔둠 ㅋ

const linkHandler = (event) => {         //a태그도 기본적으로 새로고침 기능이 있다.
  // event.preventDefault();            
  console.log(event);
  alert("click");
};

link.addEventListener("click", linkHandler);   //쿼리셀렉터로 끌어온 link에 클릭기능을 달아주자
                                                                                 //첫번째 인자는 이벤트 종류 // 두번째는 함수이다. 
const savedUsername = localStorage.getItem(USER_NAME);     //로컬스토리지에 저장된 key에 해당하는
function faintGreet(username) {                                                       //값을 불러오는 getItem
  greet.classList.remove(HIDDEN_CLASS);          //add와는 반대로 remove는 해당 class명을 지운다.
  greet.innerHTML = `hello ${username}`;        //해당 태그에 내부 글자를 바꾸는 innerHTML
}

if (savedUsername === null) {                                   //로컬스토리지에 해당 벨류가 없다면 발생된다.
  loginForm.classList.remove(HIDDEN_CLASS);             //로그인폼에서 hidden class를 제외시켜서 보이게 한다.
  loginForm.addEventListener("submit", onLoginSubmit);   //그와 동시에 서브밋 기능을 붙인다.
} else {
  faintGreet(savedUsername);           //로컬스토리지에 값이 있다면 인사를 날린다. 
}

 

<backGround.js>배경넣는 방식의 근본

const images = ["river.jpg", "lake.jpg", "tree.jpg"];    //넣을 이미지 파일의 name이다.

const chosenImage = images[parseInt(Math.random() * images.length)];   //배경을 랜덤으로 바꿀 예정인데
                                                                                 //0~1까지의 무작위수를 받아서 요래요래 하면 0,1,2의 정수가뿅
console.log(chosenImage);

const image = document.createElement("img");  //태그 자체를 생성하는 creatElement
image.src = `img/${chosenImage}`;    //방금만든 태그에 src속성을 달아준다. 실제 이미지 파일명을 제공
console.log(image);

document.body.appendChild(image);  //이제 html body에 appendChild를 통해 가장 아래 태그로 붙여준다.
                                                                  //앞쪽에 붙이기 위해서는 prepend를 사용한다고 한다.

 

<clock.js> 예쁜 시계를 달아보자.

const clock = document.querySelector("#clock");    //역시나 querySelctor로 해당 태그를 끌어온다.

clock.innerHTML = "00:00";    일단 기본값을 요래 둔다.

function getClock() {                        //시계의 동작원리를 담을 함수
  const date = new Date();                  //Date오브젝트를 통해 date를 찍어내주자.
  const hours = String(date.getHours()).padStart(2, "0");         //date는 여러 매서드를 갖는데
  const minutes = String(date.getMinutes()).padStart(2, "0");    //시각을 가져오고 분을 가져오고 초를 get어쩌구로
  const seconds = String(date.getSeconds()).padStart(2, "0");   //가져온다.   padStart는 해당 문자열을 조건에 
  clock.innerHTML = `${hours}:${minutes}:${seconds}`;              //맞춰서 반환해준다. 
}                                         //마지막에 잘 할당한 시 분 초를 태그에 붙여주면 끝
getClock();
setInterval(getClock, 1000);        //setInterval 함수는 두개의 인자를 받는다 처음은 작동할 콜백함수
// setTimeout(sayHello, 5000);     //두번째는 얼마나 시간텀을 두고 작동할지 결정하는 시간이다.

 

<quote.js> 교훈을 보여줘 보자

const quotes = [                                                                   //스스로에게 날리는 매콤한 교훈 진짜 정신차리자
  { content: "정신차리고 코드나 쳐!!!", person: "한지우" },
  { content: "세상이 만만하냐? 똑바로 안살래?", person: "한지우" },
  { content: "게을러 터져져 어쩔려고 그러냐?", person: "한지우" },
  { content: "정신 안차리면 너 굶어 뒤진다?", person: "한지우" },
  { content: "코딩공부 열심히 해라 그거라도 안하면 뭐할래?", person: "한지우" },
];

const quote = document.querySelector("#quote span:first-child");  //역시나 id로 태그불러오는데
const person = document.querySelector("#quote span:last-child");  //공백두고 자식태그를 불러온수 있다.
                                                                                                                //첫째와 막내 span을 맛깔나게 불러오자.
const randomQuote = parseInt(Math.random() * quotes.length);    //시계랑 똑같은 랜덤 불러오기 0~4사이의 정수
console.log(randomQuote);
console.log(quotes[randomQuote]);

quote.innerHTML = quotes[randomQuote].content;     //그렇게 랜덤하게 불러온 quote를 내용과 사람 분류해서
person.innerText = quotes[randomQuote].person;          //할당한다.

 

<weather.js> 오픈 API를 불러오는 근본 외부통신의 기초이다.

const API_KEY = "이건 API키야 쿠쿠루삥뽕";   //API를 따로 할당해 보았다.

const geoOkay = (position) => {                    //position이라는 매개변수를 받는다. 네이밍은 상관엄슴
  const la = position.coords.latitude;                    //위도와 경도를 할당한다.
  const lo = position.coords.longitude;
  console.log(lo, la);
  let URL = `https://api.openweathermap.org/data/2.5/weather?lat=${la}&lon=${lo}&appid=${API_KEY}&units=metric`;
  console.log(URL);            //URL은 다 다르다. 얘네는 이렇게 제공한다.
  fetch(URL)                             //fetch를 통해 비동기적으로 API데이터를 가져와 본다.
    .then((res) => res.json())        //then을 통해 비동기 data수신 완료후 작업을 진행한다. fetch는 json형식변환 필!!
    .then((data) => {                            //한번더 then을 써서 파싱된 데이터를 추후 작업한다.
      let city = document.querySelectorAll("#weather span:first-child");        //쿼리셀렉터 ALL을 그냥 쿼리셀렉터랑
      let weather = document.querySelectorAll("#weather span:last-child");  //다르게 배열로 가져오니까 유의
      //   console.log(city, " t시티");
      city[0].innerText = data.name;                                 //이제 이너 텍스트든 이너 HTML이든 써써
      weather[0].innerText = data.weather[0].main;           //할당해주면 끝
    });
};

const geoError = function () {
  alert("오우 에러");
};

navigator.geolocation.getCurrentPosition(geoOkay, geoError);   //사실 요게 중요하다.
                        //요걸 쓰면 이제 현재 유저의 위치정보를 받아올수 있다. 인자로는 첫번째는 성공시 콜백함수고  //두번째는 실패시 이뤄지는 콜백함수다. 걍 유저가 위치제공 승낙하는지 안하는지로 나눠진다.

 

<todo.js> 투두리스트를 만들어보자 뭐 CRUD의 기초가 담겼다. 쿠쿠루삥뽕

const todoForm = document.getElementById("todoform");  //getElement바이로 가져와봄 #은 노필요
const todoList = document.querySelector("#todoList");
const todoInput = todoForm.querySelector("input");      //태그종류 자체를 가져오기 때문에 태그명 쓴다.
const TODOS_KEY = "Todos";
let Todos = [];                          //투두들을 담을 어레이

const saveTodos = () => {                                           //로컬스토리지에 저장할 함수
  localStorage.setItem("Todos", JSON.stringify(Todos));   //배열형태인 todos를 안망가뜨리고
};                                                                                 //로컬스토리지에 저장하기위한 stringify

function deleteTodo(event) {                     //삭제함수
  const li = event.target.parentNode;          //해당이벤트의 target인 버튼태그의 부모노드를 할당
  li.remove();                                        //지워버림 remove로
  console.dir(li.id);
  const arr = Todos.filter((item) => {            //태그는 지워 졌지만 로컬스토리지에서도 지워야함
    return item.id != li.id;                                 //필터링을 통해 todos배열의 item의 id와 삭제버튼의 부모노드
  });                                                          //인 li에 id를 비교해서 다른애들만 남긴다 즉 일치하는애 삭제
  //   console.log(arr);
  Todos = arr;                            //그렇게 필터링된애로 재할당하고
  saveTodos();                     //로컬스토리지를 업데이트한다.
}

const paintTodo = (newTodo) => {       //새로운 todo를 그리기 위한 함수
  //   console.log(newTodo);
  const li = document.createElement("li");             //li태그를 야무지게 생성한다.
  const span = document.createElement("span");
  const button = document.createElement("button");      //요 태그들도 야무지게 생성한다.
  button.innerText = "✖";                 //버튼태그의 안에 text를 할당
  button.addEventListener("click", deleteTodo);   //그와 동시에 삭제 함수를 클릭이벤트에 할당
  li.appendChild(span);
  li.appendChild(button);               //li태그에 이제 span과 버튼태그를 붙여준다.
  li.id = newTodo.id;                        //매개변수인 newTodo에는 id랑 text가 들어있다 오브젝트다.
  span.innerText = newTodo.text;
  todoList.appendChild(li);                      //todolist에 이제 li태그를 붙여줘서 마무리
};

const submitHandler = function (event) {       //그림을 그리는 위에 함수와는 별개로 //제출로직이 담긴함수
  event.preventDefault();                                 //폼태그이기 때문에 새로고침 막고
  const newTodo = todoInput.value;           //인풋태그의 정보를 미리 받아두고
  todoInput.value = "";                                  //제출했응께 인풋태그 비워주고
  const newObj = {                     //이게 위에 페인트 todo에서 받은 매개변수가될 오브젝트
    text: newTodo,
    id: Date.now(),                      //id와 text를 갖는다. id는 단순하게 날짜로 한다 ㅋ
  };
  Todos.push(newObj);            //todos어레이에 담아주고
  saveTodos();                       //로컬스토리지에 저장해주고
  paintTodo(newObj);          //동시에 정보 정리가 잘 끝나고 그림을 그린다.
};

todoForm.addEventListener("submit", submitHandler);   //폼태그에 서브밋 이벤트를 담아준다.

function saysay(item) {           //얜 뭐냐 ㅋ
  console.log(item, " zz");
}
const getSavedTodos = localStorage.getItem(TODOS_KEY);  //자바스크립트의 첫랜더링시
// console.log(getSavedTodos);                                           //해당 키값을 확인해본다.
if (getSavedTodos !== null) {                                          //키에 해당하는 벨류가 있다면
  const parsedTodos = JSON.parse(getSavedTodos);        //json형식으로 저장된 arr를 파싱해서 가져와서
  //   console.log(parsedTodos);
  Todos = parsedTodos;                               //todos의 배열에 할당해주고
  parsedTodos.forEach(paintTodo);        //todos배열에 각아이템을 순회하면서 작동하는 배열매서드를 이용
}                                                            //해서 그림을 그려준다.

const sexyfilter = function (item) {            필터링 테스트 
  return item % 2 === 0;
};

const res = [1, 2, 3, 4].filter(sexyfilter);   //소괄호 없이 함수명만 달아보는건 안익숙해서 해봄 ㅋ
console.log(res);

 

이상으로 바닐라 자바스크립의 기초를 다시 해보았다.

결론 재밌당. ㅋㅋ