Skip to content

Conversation

@Wannys26
Copy link

@Wannys26 Wannys26 commented Sep 13, 2025

배포 링크

CEOS-vanilla-todo

느낀 점

어떤 디자인을 하면 좋을지 많이 망설이다가, 이번 기회에 피그마 공부도 해보고 태블릿으로 와이어 프레임을 그려보면서,
타이포그래피랑 사용하는 색, 반응형 디자인 등을 미리 정해두고 가는게 중요하다는 것을 느꼈습니다.
image

만드는데 애정이 갔으면 좋겠어서, 제가 자주 사용하는 형식인 달력 형태의 투두리스트를 기획해보았습니다.
2주차에 리액트로 리팩토링할 때는 사이드바 기능까지 추가해서, 사이드 바에 {할 일, 완료한 일, 다크/라이트 모드} 기능까지 추가하고 싶습니다.
위에 기능까지 추가하자니, 코드가 너무 길어질거 같아서 일단은 뺐습니다.

달력의 날짜를 클릭하면, 모달이 떠서 할일을 추가/완료/삭제 할 수 있도록 하였습니다.

image image

Review Questions

1.DOM은 무엇인가요?

개념

DOM은 웹 브라우저가 HTML 문서를 해석해서 만든 트리 구조의 객체 모델. 웹 페이지의 설계도 같은 것.
HTML 코드는 브라우저에 의해 DOM이라는 구조로 변환되고, 이걸 통해 자바스크립트 같은 프로그래밍 언어가 웹 페이지를 자유롭게 조작할 수 있음.

DOM 구조

DOM은 트리(Tree) 형태로 표현.

웹 문서의 html 태그가 가장 뿌리(Root).
그 아래에 head, body 같은 가지(Branch).
가지 밑에 p, div 같은 잎(Leaf)들이 붙어 있음

예시:

<html>
  <body>
    <h1>안녕하세요</h1>
    <p>DOM을 배워봅시다!</p>
  </body>
</html>

위 HTML은 DOM으로 변환되면 이런 트리 구조가 됨:

html
└── body
├── h1 ("안녕하세요")
└── p ("DOM을 배워봅시다!")

비유:
DOM을 레고 블록 구조라고 생각해 본다면:
HTML 코드는 조립 설명서.
DOM은 조립된 레고 집(완성 구조).
자바스크립트는 레고 집의 창문을 열고 닫거나, 벽 색을 칠하는 역할.

mozilla DOM 설명글

2.이벤트 흐름 제어(버블링 & 캡처링)이 무엇인가요?

웹 브라우저는 이벤트(클릭, 키 입력 등)가 발생했을 때, DOM 트리를 따라 이벤트를 전달하는 규칙을 가지고 있는데, 이것을 **캡처링(Capturing)**과 **버블링(Bubbling)**이라고 함.

<이벤트 흐름 단계>
이벤트가 발생하면 총 3단계를 거침:

  1. 캡처링 단계 (Capturing Phase)
    이벤트가 **문서 최상단(root, window → document → html …)**에서 시작해,
    이벤트가 발생한 타겟 요소까지 내려가는 과정

  2. 타겟 단계 (Target Phase)
    실제로 이벤트가 발생한 요소(예: 클릭)에서 실행돼요.

  3. 버블링 단계 (Bubbling Phase)
    이벤트가 다시 타겟에서 시작해 상위 요소로 거슬러 올라가는 과정.

예시

HTML 구조:

<div id="parent">
  <button id="child">Click Me</button>
</div>

자바스크립트:

document.getElementById("parent").addEventListener("click", () => {
  console.log("부모 div 클릭!");
});

document.getElementById("child").addEventListener("click", () => {
  console.log("자식 button 클릭!");
});

클릭 동작

  • 버튼 클릭 시 먼저 child의 이벤트가 실행 → 그다음 parent의 이벤트
    실행
  • 이게 바로 버블링(Bubbling). (이벤트가 아래에서 위로
    거품처럼 올라간다고 해서)

캡처링 사용법

기본적으로 브라우저는 버블링을 사용하지만, addEventListener의 세
번째 인자로 { capture: true }를 주면 캡처링 단계에서 이벤트를 잡을
수 있음.

document.getElementById("parent").addEventListener("click", () => {
  console.log("부모 div 캡처링!");
}, { capture: true });

이 경우 버튼을 클릭하면: 1. 부모 div(캡처링 단계)
2. 자식 button (타겟 단계)
3. 부모 div(버블링 단계)

이 순서로 실행됨.

버블링과 캡처링 제어

  • event.stopPropagation()
    이벤트 전파(흐름)를 막아서, 더 이상 위/아래로 전달되지 않게 할 수
    있음.

  • event.stopImmediatePropagation()
    같은 요소에 등록된 다른 이벤트 핸들러까지 막아버림.

비유로 이해하기

  • 캡처링: "엄마 → 아빠 → 아이" 순서로 내려가면서 누가 반응할지
    보는 것.\
  • 버블링: 아이가 먼저 반응하고, 그 일이 부모에게 알려져 점점 위로
    전달되는 것.

3.클로저와 스코프가 무엇인가요?

스코프(Scope)

스코프는 변수에 접근할 수 있는 범위를 말함

  • 전역 스코프: 코드 전체에서 접근 가능
  • 지역 스코프: 함수나 블록 내부에서만 접근 가능
let x = 10; // 전역

function test() {
  let y = 20; // 지역
  console.log(x); // 가능
  console.log(y); // 가능
}

console.log(x); // 가능
console.log(y); // 오류

--

클로저(Closure)

클로저는 함수와 그 함수가 선언된 스코프를 함께 기억하는 것
즉, 함수가 외부 변수에 계속 접근할 수 있음

function outer() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2

counterouter가 끝난 후에도 count에 접근 가능함

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 꼼꼼한 주석 덕분에 코드를 파악하기 수월한 것 같아요!

Copy link
Member

@lemoncurdyogurt lemoncurdyogurt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

달력까지 구현하시느라, 너무 고생많으셨습니다! 코드가 가독성있게 짜여져서 보기 좋았습니다. alert대신 모달을 활용하는 것도 인상 깊었습니다. 다음주차 과제까지 고려해서 고민하신게 보였는데, 다음주차 과제가 너무 기대가 됩니다!!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 현재 background-color에서 색상명, 16진수, rgba가 모두 혼재되어있는데 이런 것들 통일 시키면 예쁜코드가 될 것 같습니다.

Comment on lines +149 to +155
.modalContent {
background-color: white;
margin: 15% auto;
padding: 0;
border-radius: 10px;
width: 400px;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

width가 400px로 지정되어있는데, 보통 디자이너와 협업할 때 가로 너비가 375px인 점을 고려하였을 때 너무 넓은 것 같다는 생각이 들어서, modalContent의 width도 반응형으로 사이즈 조절이 되면 좋을 듯 합니다

Comment on lines +95 to +100
const year = currentDate.getFullYear();
const month = currentDate.getMonth(); // 0부터 시작 (0=1월)

// 달력 헤더 업데이트
document.getElementById('currentMonth').textContent =
`${year}년 ${month + 1}월`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 openModal 함수에서는 const monthcurrentDate.getMonth() + 1이었다면, 여기서는 따로 ${month+1}로 처리하고 있습니다. 이 변수 선언을 일치시켜서 따로 함수로 빼서 재사용 하다면 좋을 것 같습니다.

<button class="complete" onclick="toggleTodo('${selectedDay}', ${index})">
${todo.completed ? '취소' : '완료'}
</button>
<button onclick="deleteTodo('${selectedDay}', ${index})">삭제</button>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

할일을 저장할 때, selectedDay를 id로 사용하고, index로 삭제, 완료 등 모든 것을 수행하는데 코드적으로는 간편하고 좋지만 확장성을 고려하였을 때는 uuid를 활용하는 것이 유지보수 측면에서 더 좋다고 고려됩니다!

Copy link

@jungyungee jungyungee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제 너무 잘 봤습니다..!
와이어프레임 구조도 짜고 생각지도 못했던 캘린더 형식에 모달 창으로 열리는 투두라서 너무 놀랐습니다(좋은 의미로!!) 리팩토링할 것도 생각하시구,, 디자인도 깔끔하면서 눈에 잘 들어와서 좋은 거 같구요!
너무 잘하시네용,, 너무 잘하셔서 별로 할 말이 없었지만 코드 보면서 몇가지 리뷰 남겨보았습니다

<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메타 뷰포트 태그를 이용해서 반응형으로 화면이 브라우저 사이즈에 따라 표시되도록 한 점이 좋은 거 같아요..! 저는 사용하지 않았는데 다음에 는 사용해보고 싶습니당,,!

Comment on lines +17 to +33
<div class="calendarContainer">
<div class="calendarHeader">
<button id="prevMonth">◀️</button>
<h2 id="currentMonth">2025년 9월</h2>
<button id="nextMonth">▶️</button>
</div>
<div class="weekdays">
<div>일</div>
<div>월</div>
<div>화</div>
<div>수</div>
<div>목</div>
<div>금</div>
<div>토</div>
</div>
<div class="dates" id="calendarDates"></div>
</div>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

주로 div 태그 위주로 사용하셨는데, semantic tag로
section, li 등 쓰면 더 구조가 보기 좋을거 같아요..!

if (!todos[selectedDay] || todos[selectedDay].length === 0) {
todoListElement.innerHTML = '<p style="text-align: center; color: #666;">할 일이 없습니다.</p>';
return;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가된 할일이 없을 때 빈 화면만 보여주지 않고 "할 일이 없습니다" 라고 보여주는게 좋은 것 같습니다!

background-color: rgba(0, 0, 0, 0.5);
}

.modalContent {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 컨텐츠가 아무것도 없을 때는 모달 크기가 작다가 하나씩 추가할 수록 맞춰서 늘어나고, 일정 개수 이상 되면 스크롤 되는 방식이던데
min-height 등을 주어서 아예 고정 크기를 주는 것도 좋을 것 같습니다..!
스크롤되는 것은 좋은 것 같습니당

Comment on lines +194 to +197
todos[selectedDay].push({
text: todoText,
completed: false
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금 작동은 아무 문제 없이 되는 거 같은데 나중에 서버와 연동이나 다른 기능 추가를 생각하면 각 todo 당 id를 사용하는 것도 좋을 것 같아요..!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants