[노마드코더 js 웹페이지] ToDoList페이지 정리
기능들은 강의에서 다 했던 것들이라 따로 정리해서 여기다는 안 쓸거임
https://sand8594.tistory.com/13
https://sand8594.tistory.com/14
https://sand8594.tistory.com/15
https://sand8594.tistory.com/16
https://sand8594.tistory.com/17
[노마드코더] 바닐라JS 공부 7일차(To Do List)
기본 세팅 // Setup 7.0 html <!DOCTYPE html> Momentum App js const toDoForm = document.getElementById("todo-form"); const toDoInput = toDoForm.querySelector("input"); const toDoList = document.getEle..
sand8594.tistory.com
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>Momentum App</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Do+Hyeon&display=swap" rel="stylesheet">
<style>
* {
font-family: 'Do Hyeon', sans-serif;
}
</style>
<link rel = "stylesheet" href = "style.css">
</head>
<body>
<div class = "momentum">
<header>
<div class = "header-container" id = "todolist-string">To Do List</div>
<div class = "header-container" id = "login-wrap">
<form class = "hidden" id = "login-form">
<input required maxlength = "15" type = "text" placeholder = "What is your name?"/>
<button>Log In</button>
</form>
<h1 id = "greeting" class = "hidden"></h1>
</div>
<div class = "header_container" id = "date&clock">
<div id = "now_date"></div>
<div id="clock">00:00:00</div>
</div>
</header>
<form id = "todo-form">
<input required type="text" placeholder="Write a To Do and Press Eneter">
</form>
<ul id = "todo-list">
</ul>
<div id="quote">
<span></span>
<span></span>
</div>
<div id ="weather">
<span></span>
<span></span>
</div>
</div>
<script src = "js/clock.js"></script>
<script src = "js/greeting.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>
2022.01.18
momentum 클래스 설정
하얀 색 박스가 정가운데 오도록 해야함
가운데 정렬하기
.momentum {
margin: 0 auto;
}
0은 위 아래 여백을 주지 않는다는 의미이고 auto는 가로 중앙에 배치한다는 뜻이다.
박스 모델 말고 img나 text는 text-align:center 사용
나는 위를 좀 띄우고 싶으므로
margin: 75px auto로 설정했음
나머지 박스 크기들이나 이런거 다 해서 momentum 클래스 css설정은 이렇게 마무리되었음
.momentum {
margin: 75px auto;
max-width: 900px;
padding: 30px;
width: 65%;
background-color: rgb(250, 248, 248);
border-radius: 10px;
box-shadow: 5px 5px 5px 5px rgb(163, 163, 163);
}
header 설정
header의 요소 세개 (todolist글귀, greeting, 날짜)는 서로 한 줄에 출력하고 싶음
그래서 grid 쓸 거임 (flex 써도 됨)
grid에 대한 자세한 설명은 이 포스팅이 제일 좋음! 참고
https://studiomeal.com/archives/533
이번에야말로 CSS Grid를 익혀보자
이 포스트에는 실제 코드가 적용된 부분들이 있으므로, 해당 기능을 잘 지원하는 최신 웹 브라우저로 보시는게 좋습니다. (대충 인터넷 익스플로러로만 안보면 된다는 이야기) 이 튜토리얼은 “
studiomeal.com
header {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
}
부모 요소에 display:gird 이렇게 설정하고 나는 1:3:1 비율이 좋을 거 같아서 각각 fr로 작성해주었다.
header 중 greeting 설정
로그인 버튼이 별로 실용성이 없는 것 같아서 없앴고
이름 입력받는 창의 테두리를 배경과 같은 색으로 설정하도록 했음
=> js 파일 수정
loginForm.style.borderColor = chosenColor;
이거만 쓰면 됨
최종 css는 이렇게
#login-form {
border: 3px solid;
border-radius: 10px;
width: 250px;
margin: 0 auto;
}
#login-input {
font-size: 25px;
outline: none;
border: none;
text-align: center;
}
#greeting {
font-size: 30px;
}
2022.01.22
배경색 설정
갑자기 그라데이션 해서 넣고 싶음 그래서 background.js를 이렇게 변경해주었음
const colors = [
"#f7b4be",
"#f7b4be",
"#f6a88a",
"#b2dbba",
"#c3e2df",
"#d3afd5"
];
const chosenColor1 = colors[Math.floor(Math.random() * colors.length)];
const chosenColor2 = colors[Math.floor(Math.random() * colors.length)];
document.body.style.background = `linear-gradient(${chosenColor1}, ${chosenColor2})`;
근데 이렇게 하니까..?
이걸 우째해야 할까 하다가
노마드코더 챌린지에서 한 코드를 살짝 참고했음
거기는 바디에 height:100vh; width:100%로 했던데
body {
text-align: center;
height: 91vh;
}
이정도로만 넣어줬음
2022.01.21
To Do List 꾸미기
할 일 입력받는 창 다시 꾸미고 추가로 체크 버튼을 넣어서 해당 일을 했는지 안 했는지 표기해줄거임
1️⃣ 목록을 적으면 투두리스트에 대한 박스 생기기
투두리스트에 목록이 존재하냐 안 하냐로 체크해주었음
즉 todos의 길이가 0이면 없어지고 1이상이면 생기게 해주었다.
2️⃣ 마우스 올리면 체크버튼과 삭제버튼이 뜨고 벗어나면 없어지게 하기
이건 addEventListener로 각각 mouseover과 mouseout으로 관리
아 그리고 체크버튼이 눌러져 있는 상태이면 innerText 를 🗸이거로 유지되게 하였음
3️⃣ 체크버튼 누르면 글씨의 색이 바뀌고 밑줄 넣기
.style.color = chosenColor1로 해주고
밑줄은 text-decoration으로!
text-decoration: none | line-through | overline | underline | initial | inherit
- none : 선을 만들지 않습니다.
- line-through : 글자 중간에 선을 만듭니다.
- overline : 글자 위에 선을 만듭니다.
- underline : 글자 아래에 선을 만듭니다.
- initial : 기본값으로 설정합니다.
- inherit : 부모 요소의 속성값을 상속받습니다.
값 자체를 숫자로 넣어도 가능
아무튼 다 하면 이런 형태가 됨(css파일이랑 todo.js 엄청 수정했음)
수정한 todo.js 랑 css 는 이러함
ul {
list-style: none;
border: 3px solid;
}
button {
border: 0;
outline: 0;
background: none;
}
#todo-list {
width: 350px;
margin: 0 auto;
margin-top: 20px;
padding-left: 0;
}
li {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
margin: 10px;
height: 30px;
}
.li-span {
text-align: left;
margin-left: 10px;
color: #4e4c4c;
}
todo.js
const toDoForm = document.getElementById("todo-form");
const toDoInput = document.getElementById("todo-input");
const toDoList = document.getElementById("todo-list");
toDoInput.style.background = `linear-gradient(${chosenColor1}, ${chosenColor2})`;
const TODOS_KEY = "todos";
const UNCHECKED_CLASSNAME = "unchecked"
let toDos = [];
function saveToDos() {
localStorage.setItem(TODOS_KEY, JSON.stringify(toDos)); // localStorage에 문자열 형태로 넣어줌
}
function deleteToDo(e) {
const li = e.target.parentElement; // 부모요소 얻기
//const li = this.parentElement;와 같음
li.remove(); // 해당 부모 요소 삭제
toDos = toDos.filter((todo) => todo.id !== parseInt(li.id)); // 배열에서도 찾아서 삭제해줌
// id는 문자열형태로 보이기 때문에 비교를 위해서 int로 바꿔줘야함
saveToDos(); // 새로운 toDos로 저장
if (toDos.length == 0) {
toDoList.style.display = "none";
}
}
function checkToDo(e) {
const li = e.target.parentElement; // 부모 요소 얻기
const checkBtn = li.children[0]; // 부모의 자식들 중 첫번째
const span = li.children[1]; // 두번쨰
if (li.className == UNCHECKED_CLASSNAME) { // li의 클래스네임 확인 체크되어있지 않은 상태였다면
span.style.textDecoration = "line-through";
span.style.color = chosenColor1;
checkBtn.innerText = "🗸"; // 체크표시하고 글자밑줄, 색 바꿔줌
li.classList.remove(UNCHECKED_CLASSNAME); // 그리고 unchecked지워줌
}else{ // 체크되어 있는 상태였다면
span.style.textDecoration = "none";
span.style.color = "#4e4c4c";
checkBtn.innerText = " "; // 원 상태로 복귀
li.classList.add(UNCHECKED_CLASSNAME); // 다시 unchecked 추가
}
}
function paintToDo(newTodoObj) {
toDoList.style.display = "";
const li = document.createElement("li"); // li태그 생성
const span = document.createElement("span"); // span태그 생성
const removeBtn = document.createElement("button"); // remove button 태그 생성
const checkBtn = document.createElement("button"); // check button 태그 생성;
span.innerText = newTodoObj.text; // span 내에 문구를 넣음
removeBtn.innerText = "🗑"; // button 내에 x를 넣음
checkBtn.innerText = " ";
removeBtn.style.color = chosenColor1;
removeBtn.style.fontSize = "20px";
checkBtn.style.fontSize = "20px"
checkBtn.style.color = chosenColor1;
checkBtn.style.borderColor = chosenColor1;
checkBtn.style.borderRight = "3px solid"
span.classList.add("li-span");
removeBtn.classList.add(HIDDEN_CLASSNAME);
removeBtn.classList.add("removeBtn");
checkBtn.classList.add("checkBtn");
li.id = newTodoObj.id; // li태그에 id부여
li.appendChild(checkBtn);
li.appendChild(span); // li로 span 감싸기
li.appendChild(removeBtn); // li로 button 감싸기
li.classList.add(UNCHECKED_CLASSNAME);
toDoList.appendChild(li); // todoList 안에 li 넣기
checkBtn.addEventListener("click", checkToDo);
li.addEventListener("mouseover", function() {
removeBtn.classList.remove(HIDDEN_CLASSNAME);
checkBtn.innerText = "🗸";
})
li.addEventListener("mouseout", function() {
removeBtn.classList.add(HIDDEN_CLASSNAME);
if(li.className == UNCHECKED_CLASSNAME) {
checkBtn.innerText = " ";
}else {
checkBtn.innerText = "🗸";
}
})
removeBtn.addEventListener("click", deleteToDo); // click시 해당 목록 삭제
checkBtn.addEventListener("click", checkToDo)
toDoList.classList.remove(HIDDEN_CLASSNAME);
toDoList.style.borderRadius = "5px";
toDoList.style.borderColor = chosenColor1;
}
function handleToDoSubmit(e) {
e.preventDefault(); // 새로고침 방지
const newTodo = toDoInput.value; // todoInput의 value를 가져와서 저장
toDoInput.value = ""; // 초기화시켜줌
const newTodoObj = { // 각 요소들을 분리해주기 위해 id가 부여된 객체 생성
text: newTodo,
id: Date.now(),
};
toDos.push(newTodoObj); // newTodoObj를 배열에 저장
paintToDo(newTodoObj); // newTodoObj를 목록에 추가함
saveToDos();
}
toDoForm.addEventListener("submit", handleToDoSubmit); // 엔터키 누르면 함수 호출
const savedToDos = localStorage.getItem(TODOS_KEY); // localStorge에서 아이템 얻기
if (savedToDos !== null) { // 비어있지 않다면
const parsedToDos = JSON.parse(savedToDos); // 배열로 바꿔줌
toDos = parsedToDos; // toDos배열에 parsedToDos배열을 대입
parsedToDos.forEach(paintToDo); // 각 요소에 대해 paintToDo함수 실행
}
여기서 문제점!! 내가 한 상태로만 하면 새로고침 후에 내가 했다고 체크해둔 요소가 다시 초기화 됨...
이것도 localStorage 써야하나..? 잘 모르겠음 일어나서 해야지
2022.01.23
해결하지 못했던 체크상태 기억하기를 해두려고 함
각각 li에 id를 넣어줬으니 그걸 활용해서 localStorage에 넣은 다음 항상 체크하게 하면 되지 않을까?
시벌.... 체크 눌러진 애들을 localStorage에 저장하기 까진 됐는데 그걸 활용해서 밑줄 긋기가 안 됨...
일단 저장하는 건 이렇게 했음
let checkToDos = [];
function saveCheckedToDos() {
localStorage.setItem(CHECECKTODOS_KEY, JSON.stringify(checkToDos)); // localStorage에 저장
}
function checkToDo(e) {
const li = e.target.parentElement; // 부모 요소 얻기
const checkBtn = li.children[0]; // 부모의 자식들 중 첫번째
const span = li.children[1]; // 두번쨰
if (li.className == UNCHECKED_CLASSNAME) { // li의 클래스네임 확인 체크되어있지 않은 상태였다면
span.style.textDecoration = "line-through";
span.style.color = chosenColor1;
checkBtn.innerText = "🗸"; // 체크표시하고 글자밑줄, 색 바꿔줌
li.classList.remove(UNCHECKED_CLASSNAME); // 그리고 unchecked지워줌
var checkedTodoObj;
for(var i = 0; i < toDos.length ; i++) {
if (parseInt(li.id) === toDos[i].id){
checkedTodoObj = toDos[i];
}
}
checkToDos.push(checkedTodoObj); // checkToDos배열에 넣기
}else{ // 체크되어 있는 상태였다면
span.style.textDecoration = "none";
span.style.color = "#4e4c4c";
checkBtn.innerText = " "; // 원 상태로 복귀
li.classList.add(UNCHECKED_CLASSNAME); // 다시 unchecked 추가
checkToDos = checkToDos.filter((checktodo) => checktodo.id !== parseInt(li.id));
}
saveCheckedToDos();
}
목록들 저장한 거 처럼 밑에서 따로 처리해주려고 했는데 안 됨...일단 제출해야해서 포기하고 이렇게 마무리..
ㄴ
명언이랑 날씨정보 꾸미기
명언은 그냥 기울임꼴 넣어서 지금처럼 넣어줄 거고 날씨정보는 왼쪽 상단에 넣어줄거다.
font-sytle
font-style: normal | italic | oblique | initial | inherit ;
- normal : 보통 모양입니다.
- italic : 기울임꼴입니다.
- oblique : 기울임꼴입니다.
- initial : 기본값으로 설정합니다.
- inherit : 부모 요소의 속성값을 상속받습니다.
position
positon: static | reletive | absolute | fixed | stickey ;
- static : 기준 없음(배치 불가능 / 기본값)
- relative : 요소 자기 자신을 기준으로 배치
- absolute: 부모(조상) 요소를 기준으로 배치
- fixed : 뷰 포트 기준으로 배치
- stickey : 스크롤 영역 기준으로 배치
추가로 Top, Bottom, Left, Right 설정
- top : 요소의 position 기준에 맞는 위쪽에서의 거리(위치)를 설정
- bottom : 요소의 position 기준에 맞는 아래쪽에서의 거리(위치)를 설정
- left : 요소의 position 기준에 맞는 왼쪽에서의 거리(위치)를 설정
- right : 요소의 position 기준에 맞는 오른쪽에서의 거리(위치)를 설정
나는 왼쪽 상단에 넣고 싶으니까 positon: absolute; left: 0; top: 0; 이렇게 설정해주었다.
최종적으로 완성!
최종 코드는 여기
https://github.com/juhui88/JavaScriptStudy
GitHub - juhui88/JavaScriptStudy
Contribute to juhui88/JavaScriptStudy development by creating an account on GitHub.
github.com