-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[1주차] 김류원 미션 제출합니다. #10
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,33 @@ | ||
const addBtn = document.querySelector('.addBtn'); | ||
const TodoInput = document.querySelector('.TodoInput'); | ||
const todoList = document.querySelector('.todoList'); | ||
const todoForm = document.querySelector('.writeTodoForm'); | ||
const todoForm = document.getElementById('todoForm'); | ||
|
||
let todos = []; | ||
|
||
// localStorage에서 todos 불러오기 | ||
function loadTodos() { | ||
const savedTodos = localStorage.getItem('todos'); | ||
if (savedTodos) { | ||
todos = JSON.parse(savedTodos); | ||
todos.forEach(todo => createTodoElement(todo.text, todo.completed)); | ||
} | ||
} | ||
|
||
// localStorage에 todos 저장 | ||
function saveTodos() { | ||
localStorage.setItem('todos', JSON.stringify(todos)); | ||
} | ||
|
||
function addTodo(e) { | ||
e.preventDefault(); | ||
|
||
const Todo = TodoInput.value.trim(); | ||
|
||
if (Todo) { | ||
createTodoElement(Todo); | ||
createTodoElement(Todo, false); | ||
todos.push({ text: Todo, completed: false }); | ||
saveTodos(); | ||
TodoInput.value = ''; | ||
} else { | ||
alert('To Do를 입력하세요'); | ||
|
@@ -19,37 +37,57 @@ function addTodo(e) { | |
todoForm.addEventListener('submit', addTodo); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
// 투두 추가 함수 | ||
function createTodoElement(Todo) { | ||
function createTodoElement(Todo, isCompleted) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. createTodoElement() 함수 내에 투두 텍스트 생성 / 토글 생성 / 삭제 버튼 생성 로직을 별도의 함수로 빼낸 후, |
||
const listItem = document.createElement('li'); | ||
listItem.classList.add('animate-slide-down'); | ||
if (isCompleted) { | ||
listItem.classList.add('completed'); | ||
} | ||
|
||
// 완료 토글 아이콘 | ||
const toggleIcon = document.createElement('img'); | ||
toggleIcon.src = './icon/notCheck.svg'; | ||
toggleIcon.alt = 'Toggle unComplete'; | ||
toggleIcon.src = isCompleted ? './icon/checkComplete.svg' : './icon/notCheck.svg'; | ||
toggleIcon.alt = isCompleted ? 'Toggle Complete' : 'Toggle unComplete'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
toggleIcon.classList.add('toggle-icon'); | ||
|
||
// 투두 텍스트 | ||
const todoText = document.createElement('span'); | ||
todoText.textContent = Todo; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기에서 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 변수명을 쓸 때, Todo보다 lowercamelcase 컨벤션에 맞추어 todo로 작성하는것이 좋을 것 같아요! |
||
if (isCompleted) { | ||
todoText.classList.add('completed-text'); | ||
} | ||
|
||
toggleIcon.addEventListener('click', () => { | ||
listItem.classList.toggle('completed'); | ||
todoText.classList.toggle('completed-text'); | ||
if (listItem.classList.contains('completed')) { | ||
const isNowCompleted = listItem.classList.contains('completed'); | ||
if (isNowCompleted) { | ||
toggleIcon.src = './icon/checkComplete.svg'; | ||
toggleIcon.alt = 'Toggle Complete'; | ||
} else { | ||
toggleIcon.src = './icon/notCheck.svg'; | ||
toggleIcon.alt = 'Toggle unComplete'; | ||
} | ||
// localStorage 업데이트 | ||
const index = todos.findIndex(item => item.text === Todo); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 류원님의 투두 리스트에서 동일한 내용을 가진 항목을 추가하고, 완료하면 첫번째 항목의 completed 값만 true로 변경되고 두번째 항목의 completed 값은 변경되지 않는 것을 확인할 수 있어요. 지금 코드를 보면, 항목을 고유하게 식별할 수 있는 값이 없고, 텍스트만을 기준으로 항목을 찾고 업데이트하는 것으로 보여요. 때문에, 텍스트가 동일한 두 항목이 있을 경우 제대로 구분되지 않고 한 항목만 업데이트되는 문제가 발생하는 것 같아요. 이러한 문제를 해결하려면, 각각의 항목을 텍스트 내용에 상관없이 고유하게 식별할 수 있어야 하는데, text를 구분 기준으로 삼기 보다, 고유한 id를 추가해서 Id를 기준으로 식별하는 것이 좋아보여요!
-> ... 이런식으로요! https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex |
||
if (index !== -1) { | ||
todos[index].completed = isNowCompleted; | ||
saveTodos(); | ||
} | ||
}); | ||
|
||
// 삭제 버튼 | ||
const deleteBtn = document.createElement('button'); | ||
deleteBtn.textContent = '삭제'; | ||
deleteBtn.textContent = 'Del'; | ||
deleteBtn.classList.add('delete-btn'); | ||
deleteBtn.addEventListener('click', () => { | ||
todoList.removeChild(listItem); | ||
listItem.classList.add('animate-fade-out'); | ||
setTimeout(() => { | ||
todoList.removeChild(listItem); | ||
// localStorage에서 삭제 | ||
todos = todos.filter(item => item.text !== Todo); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 할일 항목을 삭제할때도, 텍스트 기준으로 비교되어서 |
||
saveTodos(); | ||
}, 300); | ||
}); | ||
|
||
// HTML 구조에 맞게 요소 추가 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다혜님이 말씀해주신것처럼, appendchild 메서드로 요소를 하나씩 추가하는 것보다 한번에 추가하는 방법을 사용하는게 최적화 측면에서도 좋아보여요! 가빈께 남긴 코드리뷰중에, 리플로우와 리페인팅에 대한 설명을 참고해보시면 좋을 것 같아요! |
||
|
@@ -71,9 +109,11 @@ function formatDateKorean(date) { | |
return `${month} ${day}일 ${dayOfWeek}`; | ||
} | ||
|
||
// 페이지 로드 시 오늘 날짜 표시 | ||
// 페이지 로드 시 실행 | ||
document.addEventListener('DOMContentLoaded', () => { | ||
const todayDateElement = document.getElementById('todayDate'); | ||
const today = new Date(); | ||
todayDateElement.textContent = formatDateKorean(today); | ||
|
||
loadTodos(); // localStorage에서 todos 불러오기 | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
/*라이브러리*/ | ||
@import url("https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/static/pretendard.css"); | ||
html{ | ||
font-family: "Pretendard"; | ||
} | ||
* { | ||
margin: 0; | ||
padding: 0; | ||
|
@@ -56,35 +60,118 @@ | |
margin-top: 20px; | ||
display: flex; | ||
flex-direction: column; | ||
background-color: #c3ccff; | ||
background-color: #d6ddff; | ||
} | ||
.check_icon { | ||
width: 20px; | ||
height: 20px; | ||
margin: 0 15px 0 0px; | ||
fill: #788bff; | ||
|
||
|
||
} | ||
.writeTodoForm { | ||
width: 100%; | ||
height: 52px; | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
padding: 0 15px 0 15px; | ||
} | ||
.writeTodoForm > .TodoInput { | ||
width: 100%; | ||
height: 50px; | ||
outline: none; | ||
border: none; | ||
color: #788bff; | ||
background-color: transparent; | ||
font-weight: 700; | ||
font-size: 0.8rem; | ||
} | ||
.writeTodoForm > .TodoInput::placeholder{ | ||
color: #788bff; | ||
} | ||
.writeTodoForm > .addBtn, .delete-btn { | ||
cursor: pointer; | ||
background-color: #788bff; | ||
width: 36px; | ||
height: 22px; | ||
border-radius: 10px; | ||
font-size: 0.75rem; | ||
color: white; | ||
padding: 2px; | ||
border: none; | ||
transition: background-color .3s, color .3s; | ||
} | ||
.writeTodoForm > .addBtn:hover, .delete-btn:hover{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hover까지 처리해주신거 너무 좋아요👍👍 |
||
background-color: white; | ||
color: #788bff; | ||
} | ||
.todoList{ | ||
width:100%; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
.todoList li { | ||
width: 100%; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
border-radius: 10px; | ||
margin-top: 20px; | ||
display: flex; | ||
flex-direction: row; | ||
align-items: center; | ||
background-color: #d6ddff; | ||
height: 50px; | ||
padding: 0 15px 0 15px; | ||
color: #788bff; | ||
font-weight: 700; | ||
font-size: 0.8rem; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다른 값들은 |
||
} | ||
|
||
.completed-text { | ||
.todoList .completed-text { | ||
text-decoration: line-through; | ||
color: #888; | ||
color: #7d808e; | ||
} | ||
|
||
.toggle-icon, .delete-icon { | ||
.todoList .toggle-icon, .delete-icon { | ||
width: 20px; | ||
height: 20px; | ||
cursor: pointer; | ||
} | ||
|
||
.toggle-icon { | ||
.todoList .toggle-icon { | ||
margin-right: 10px; | ||
} | ||
|
||
.delete-icon { | ||
.todoList .delete-icon { | ||
margin-left: auto; | ||
} | ||
|
||
span { | ||
.todoList span { | ||
flex-grow: 1; | ||
} | ||
} | ||
|
||
@keyframes slideDownFadeIn { | ||
from { | ||
opacity: 0; | ||
transform: translateY(-20px); | ||
} | ||
to { | ||
opacity: 1; | ||
transform: translateY(0); | ||
} | ||
} | ||
.animate-slide-down { | ||
animation: slideDownFadeIn 0.2s ease-out forwards; | ||
} | ||
/* */ | ||
|
||
/* 할일 삭제 애니메이션 */ | ||
@keyframes fadeOutScaleDown { | ||
from { | ||
opacity: 1; | ||
transform: scale(1); | ||
} | ||
to { | ||
opacity: 0; | ||
transform: scale(0.9); | ||
transform: translateY(+10px); | ||
} | ||
} | ||
.animate-fade-out { | ||
animation: fadeOutScaleDown 0.2s ease-out forwards; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서도
TodoInput
이나Todo
처럼 camelCase를 사용하지 않는 부분이 있어서, 따로 기준을 가지고 계신지 궁금해요!