반응형

 

 
OMG
아티스트
NewJeans
앨범
NewJeans 'OMG'
발매일
2023.01.02

완성본링크

https://cokeholic-kim.github.io/VanillaJS-TODO/

 

Document

 

cokeholic-kim.github.io

이번에 노마드코더 자바스크립트 챌린지 강의를 자바스크립트 복습도 할 겸 도전하게 되었다. 정말 기초부터 시작해서 크게 어렵지 않게 따라 할 수 있고 다 배우면 요런 투두리스트사이트를 하나 만들 수 있다. 

 

코드를 한번 보자.

 

index.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">
    <title>Document</title>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <div id="login">
        <div>
            <h1 class="" id="greeting">Welcome</h1>
            <form class="" id="login-form">
                <input type="text" placeholder="이름을 알려주세요">
            </form>
        </div>
    </div>
    <header>
        <h2 id="clock">00:00:00</h2>
    </header>
    <div id="content">
        <form id="todo-form">
            <input type="text" placeholder="Write a To Do and press Enter">
        </form>
        <ul id="todo-list"></ul>
    </div>
    <footer>
        <div id="quote">
            <span>Daily advice :</span>
            <span></span>
        </div>
        <div id="weather">
            <span></span>
            <span></span>
        </div>
    </footer>
    <div id="background"></div>
</body>
<script src="src/login.js"></script>
<script src="src/timer.js"></script>
<script src="src/weather.js"></script>
<script src="src/todo.js"></script>
<script src="src/backgroundimg.js"></script>
<script src="src/advice.js"></script>
</html>

HTML에는 로그인을 할수있는 부분과 콘텐츠 부분 그리고 뒤에 보일 배경 div들을 만들어놓았다. 자바스크립트는 기능별로 파일을 만들어서 사용한다.

 

제일처음 login.js부분을 보자

 

login.js

const loginInput = document.querySelector("#login-form input")
const loginForm = document.querySelector("#login-form")
let UserId = ""
loginForm.addEventListener("submit",(e)=>{
    e.preventDefault();
    UserId = loginInput.value;
    document.querySelector("#login").classList.add('hidden')
    console.log(UserId)

    if(UserId){
        savedToDos = localStorage.getItem(UserId);
        if(savedToDos){
            const parsedTodos = JSON.parse(savedToDos)
            toDos = parsedTodos
            parsedTodos.forEach(newTodo => {
                paintTodo(newTodo)
            });
        }
    }
    
})

로그인폼에서 submit이벤트가 발생하면 창이 새로고침되는 이벤트를 막아주고

Input태그에 입력된값을 UserId 변수에 저장한다.

그 후 로그인창은 hidden클래스를 추가해서 안 보이게 숨겨준다.

UserId가 입력되었을때 로컬저장소에 UserId키로 저장한 값이 있다면

값을 받아와서 forEach구문으로 todolist에 뿌려준다

아래에 로컬스토리지 부분은 todolist 쪽에서 사용하는 기능인데

submit 될 때 다시 값을 읽어와야 해서 완전히 분리는 못했다.

localstorageAPI는 todolist구문에서 설명하겠다.

 

timer.js

const timeContainer = document.querySelector("#clock")

function timer(){
    const now = new Date()
    timeContainer.innerText = 
    `${now.getHours()}:${String(now.getMinutes()).padStart(2,"0")}:${String(now.getSeconds()).padStart(2,"0")}`
}
timer()
setInterval(timer,1000)

현재시간을 알려주는 함수 부분이다. new Date() 로 현재의 시간을 받고 아래에서 innerText로 

now.getHours() : 시간

now.getMinutes() : 분

now.getSeconds() : 초 

값들을 넣어준다. 여기서 padStart라는 메서드를 사용했는데 이 메서드로 원래 6 이렇게 한 개만 보이던 숫자를 06처럼 앞에 0을 붙여서 2글자로 만들어준다 이미 두 글자이면 같은 글자가나 온다 padStart는 문자열에만 사용가능하기 때문에 String으로 숫자를 문자열로 변경한 다음 사용해 줬다.

 

시간을 초가 바뀔 때마다 새로 그려줘 야하기 때문에 setInterval로 1초마다 새로 시간을 받아오고 그려주게 했다.

setInterval을 쓰면 1초가 지난 뒤에 함수가 실행되기 때문에 처음 창을 열 때 아무것도 실행되고 있지 않기 때문에 timer() 함수를 호출해서 한번 먼저 실행되게 해 줬다.

 

weather.js

const API_KEY = 'apikey'

async function onGeoOk(position){
    const lat = position.coords.latitude
    const lng = position.coords.longitude
    const API_URL = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${API_KEY}&units=metric`
    
    fetch(API_URL).then(res => res.json()).then(data=>{
        const city = document.querySelector('#weather span:first-child')
        const weather = document.querySelector('#weather span:last-child')
        city.innerText = `${data.name} :`
        weather.innerText = `${data.weather[0].main} / temp ${data.main.temp}`
    })
}
function onGeoError(){
    alert("can't find you")
}

navigator.geolocation.getCurrentPosition(onGeoOk,onGeoError)

이 구문은 openWeathermapAPI를 사용하는 구문으로 현재위치를 받아서 API에서 현재위치의 기온 위치이름 날씨를 받아온다.

 

현재위치는

navigator.geolocation.getCurrentPosition(성공했을 때실행될 함수, 실패할 때실행될 함수)로 받아올 수 있다.

현재위치의 위도경도를 저장하고 API_URL문자열에 삽입해서 fetch로 자료를 요청해 받아 온다음

자료를 html에 넣어준다.

 

todo.js

const toDoForm = document.getElementById("todo-form")
const toDoInput = toDoForm.querySelector("input")
const toDoList = document.getElementById("todo-list")

let toDos = [];
let savedToDos

function saveTodos(){
    localStorage.setItem(UserId,JSON.stringify(toDos))
}

function deleteToDo(e){
    const li = e.target.parentElement
    li.remove()
    toDos = toDos.filter(toDo => toDo.id !== Number(li.id));
    saveTodos()
}

function paintTodo(newTodoObj){
    const li = document.createElement('li')
    li.id = newTodoObj.id
    const span = document.createElement('span')
    const button = document.createElement('button')
    button.innerText = "❌"
    button.addEventListener('click',deleteToDo)
    li.appendChild(span);
    li.appendChild(button);
    span.innerText = newTodoObj.text;
    toDoList.appendChild(li)
}

function handleTodoSubmit(e){
    e.preventDefault()
    const newTodo = toDoInput.value
    toDoInput.value = ""
    const newTodoObj = {text:newTodo,id:Date.now()}
    toDos.push(newTodoObj)
    paintTodo(newTodoObj)
    saveTodos()
}

toDoForm.addEventListener("submit",handleTodoSubmit)

 todolist사이트의 꽃인 todolist를 만들어주는 구문이다

localstorage를 사용해서 새로고침을 해도 작성했던 todolist가 사라지지 않는다.

작동을 설명해 주자면 todolist를 작성하는 input에 할 일을 작성하고 엔터를 누르면

submit이벤트가 발생하게 되고 submit 이벤트가 발생하면 handleTodoSubmit함수가 실행된다. 

 

handleTodoSubmit

function handleTodoSubmit(e){
    e.preventDefault() //새로고침되는 이벤트를 막는다
    const newTodo = toDoInput.value //인풋태그에 입력된값을 newToDo라는 변수에저장
    toDoInput.value = "" //인풋태그를 비워줌
    //입력받은값을 객체로만든다 text키에 입력받은값,id키에 현재시간(밀리초단위)
    const newTodoObj = {text:newTodo,id:Date.now()} //id는 나중에 삭제할때 값을 구분하기위해사용
    toDos.push(newTodoObj) //객체를 toDos배열에 넣어준다.
    paintTodo(newTodoObj) //객체를 넘겨받아서 태그를 만들고 태그에값을넣은다음 추가해주는함수
    saveTodos() //toDos배열을 localStorage에 저장해주는 함수.
}

paintTodo

function paintTodo(newTodoObj){
    const li = document.createElement('li') //li태그생성
    li.id = newTodoObj.id //li태그에 id를 추가 ,,객체의id 현재시간(밀리초)
    const span = document.createElement('span') //span태그 생성
    const button = document.createElement('button')//button태그 생성
    button.innerText = "❌" // == <button>❌</button>
    button.addEventListener('click',deleteToDo) //button에 클릭이벤트 생성
    li.appendChild(span); // == <li><span></span></li>
    li.appendChild(button); // == <li><span></span><button></button></li>
    span.innerText = newTodoObj.text; //<span>{newTodoObj.text}<span> 작성한 할일이 들어감
    toDoList.appendChild(li) //li를 todolist가 있는 ul에 붙여줌
}

saveTodos

function saveTodos(){
    localStorage.setItem(UserId,JSON.stringify(toDos))
    //localStorage.setItem(저장할키,저장할내용)
}

userId를 키값으로 저장해서 같은 유저아이디로 들어와야 같은 값을 저장할 수 있고 읽을 수 있다.

다른 키로 들어오면 다른 키에 저장된다.

JSON.stringify()는 값이나 객체를 JSON문자열로 변환시켜 준다.

(localStorage에는 문자열만 저장되기 때문에 문자열로 바꿔야 한다.)

 

이제 값을 저장했으니 새로고침 했을 때 값을 불러와서 다시 paintTodo로 그려주면 된다.

 

이 구문이 아까 login에 있던 구문이다.

if(UserId){ //로그인한값이있는지 검사
        savedToDos = localStorage.getItem(UserId); //로그인한 아이디로 localstorage에서 값을 받아옴
        if(savedToDos){ //입력한아이디로 localstorage에서 받아온값이 있으면 실행
            const parsedTodos = JSON.parse(savedToDos) //문자열로만든 값을 다시 배열로바꿔준다.
            toDos = parsedTodos //toDos변수에 받아온값을 넣어준다 넣어주지않으면 
            //새로 todolist를 입력했을때 toDos값이 비어있기때문에 localStorage값이 새로 입력된다.
            parsedTodos.forEach(newTodo => { //받아온값을 forEach로 paintTodo함수를 다시돌려준다.
                paintTodo(newTodo)
            });
        }
    }

삭제기능

deleteToDo

function deleteToDo(e){
    const li = e.target.parentElement //클릭한버튼의 부모요소인li를 받아옴
    li.remove() //받아온부모요소인li를 지워줌
    toDos = toDos.filter(toDo => toDo.id !== Number(li.id)); 
    //toDos에서 filter를 돌려서 클릭한li요소와 같지않은값들을 리턴. 해서 toDos에 넣어줌
    saveTodos() //localStorage업데이트
}

 

값이 변경될 때마다 toDos배열을 변경시키고 변경된 toDos값을 localStorage에 저장해 주는 방식이다.

 

 

backgroundimg.js

const background = document.querySelector("#background")
const imgs = ['bg1','bg2','bg3','bg4','bg5','bg6','bg7','bg8']
const random = Math.floor(Math.random()*imgs.length)
background.style.background = `url(./imgs/${imgs[random]}.jpg)`
background.style.backgroundSize =  'cover'

 이미지의 이름을 배열로 만들고 이미지배열길이범위만큼 랜덤한숫자를 만들어서 랜덤 하게 이미지를 받아올수있게 해서 넣어줬다. 새로고침될때마다 랜덤숫자가 바뀌게되고 랜덤하게 배경이미지를 받아올 수 있다.

 

advice.js

fetch("https://api.adviceslip.com/advice").then(res=>res.json()).then(
    data => document.querySelector('#quote span:last-child').innerText=(data.slip.advice)
)

명언을 랜덤 하게 보여주는 구문이다 . 원래 수업에서는 배열에 명언을 넣어놓고 랜덤하게 하나씩받아와서 html에 넣어주는 거였는데 명언을 구할시간도 없고 이쪽이더 공부하기 좋아보여서 그냥 랜덤하게 명언을 보여주는 api에 요청해서 값을 받아서 넣어주었다.

 

aaa로 들어가서 todo를 작성해 줬다.

 

bbb로 로그인해서 들어가면

아무런 값도 뜨지 않는다.

 

로컬스토리지를 들어가서 보면 각각 다른 키에 저장되어 있는 걸 볼 수 있다.

 

로컬스토리지는 f12키나 개발자도구에 들어가서 애플리케이션에 들어가면 볼 수 있다.

 

내용자체가 되게 어렵지는 않았지만 내가 따로 더 추가해서 로그인한 사람에 따라 다르게 보이는 기능을 추가해 줬다. 제대로 로그인기능을 만들어서 해도 좋을 것 같다. 혹시 설명에 이해가 안 가는 부분이 있다면 댓글로 알려주시면 확인해 보겠습니다. 

 

반응형

+ Recent posts