달력 구현 완료 🤩
classList 이용해서 동적으로 글자 색 바꾸기
어제 풀이에서 이어서
실행이 안 되는 것도 아닌데 console 창에 계속도 아니고 불규칙적으로 뜨던 문제의 오류는 다음과 같다.
Uncaught TypeError: Cannot set properties of undefined (setting 'innerHTML')
at clickBtn (index.js:56)
at HTMLButtonElement.
innerHTML 속성이 부여된 요소인 < td >에 innerHTML 속성을 쓸 수 없다는 뜻 같다.
테스트를 해보니, 다음 달을 클릭했을 때, 달력 안에 적힐 날짜(숫자)들이, 현재 존재하는 35개의 셀 안에, 마지막 숫자까지 채 다 적히지 못하고 중간에 끊겼을 때만 불규칙적으로 뜨는 오류였다. 더 이상 값을 채워 넣을 셀 즉, < td >가 없어서 innerHTML을 쓸 수 없는 것 같다.
💡 해결 방법
TableRow insertCell() Method 참고
clickBtn 함수의 본문의 일부를 수정했다.
if 구문을 통해 위와 같은 오류가 뜨는 경우 테이블 밑에 1줄의 행(7개의 셀)을 추가로 만들어 잘린 날짜들이 뜨도록 해주었다.
그러나, 이렇게 하니까 if 구문을 통해 1줄의 행이 만들어진 후 버튼을 눌러 그 행이 필요없는 달의 달력이 화면에 뜨더라도 이미 만들어진 행은 삭제가 되지 않는
문제가 발생했다.
이를 해결하기 위해 else 구문 안에서 기존의 테이블을 아예 없애준 후, 따로 새 파일을 만들어 이미 HTML 문서에 있는 테이블 구현 코드를 그대로 옮겨주었고, 이를 fetch API를 이용해 가져와서 35개의 셀을 가진 테이블을 다시 만들어주었다.
💡 수정한 코드
const td_length = td.length;
if (currMonthLastDate > td_length - currMonthFirstDay) {
// table 맨 아래에 1개의 행(7개의 셀) 추가
function addRow (tableID) {
const table = document.querySelector(tableID);
const newRow = table.insertRow(-1); // 행 1개 추가
for (let i = 0; i < 7; i++) { // 그 행에 셀 7개 추가
newRow.insertCell(i);
}
for (let i = 0; i < currMonthLastDate; i++) {
td[i+currMonthFirstDay].innerHTML = date_start;
date_start++;
}
}
addRow('.calendar');
} else {
// 기존 table을 아예 없앴다가, 총 5줄/셀 35개짜리 table을 다시 만듦
const table = document.querySelector('.calendar');
const article = document.querySelector('article');
table.innerHTML = '';
fetch('table').then(function(response) {
response.text().then(function(text) {
article.innerHTML = text;
for (let i = 0; i < currMonthLastDate; i++) {
td[i+currMonthFirstDay].innerHTML = date_start;
date_start++;
}
})
});
}
실행이 되긴 되는데...
위의 코드는 다행히 실행은 잘 된다. 의도했던 대로 좌우 버튼을 클릭할 때마다 테이블이 늘어났다 줄었다 한다. 어제 밤에 그렇게 다 끝난 줄 알고 최종 코드를 옮겨 적고 있었다...
그런데 마지막 테스트를 해보다가 새로운 문제를 발견했다. 이렇게 하니까 날짜를 클릭해도
현재 월을 제외한 다른 월에서 글자 색깔이 변하지 않는
문제가 발생했다. 좌측 화살표를 클릭하면 아예 안 바뀌고, 우측 화살표를 클릭해도 바로 다음 월 이후로 아예 안 바뀐다. 7.2.까지는 문제가 없던 부분이라 7.3.에서 잘못 건드린 듯하다.
중구난방으로 적혀 있던 코드에 이것저것 해보다가 더 지저분해지기만 하는 결과를 초래했다.
오류를 찾다가 안 돼서 차라리 7.3. 오류를 다시 해결하기 위해 다른 방법을 써보기로 했다. 두 가지 시도를 해봤다.
첫 번째로, 위에서 시도했던 행/셀을 추가하는 방법
말고, 진짜 달력들처럼 하나의 셀에 두 개의 숫자를 넣기 위해 행을 나누는 방법
을 시도해 봤는데 아래 if 조건문의 본문을 채우지 못했다. rowspan으로 행을 합치는 거 말고, 이미 존재하는 행을 동적으로 아래, 위 반으로 나누는 건 못 하는 건가.
if (currMonthLastDate > td_length - currMonthFirstDay) { // 5줄이 넘어가는 달
if (currMonthFirstDay === 5) {
// 1일이 금욜에 시작하는 달 (31이 튀어나옴)
// td[28]에 24, 31 삽입
} else if (currMonthFirstDay === 6) {
if (currMonthLastDate === 30) {
// 1일이 토욜에 시작, 30으로 끝나는 달 (30이 튀어나옴)
// td[28]에 23과 30 삽입
} else if (currMonthLastDate === 31) {
// 1일이 토욜에 시작, 31로 끝나는 달 (30, 31이 튀어나옴)
// td[28]에 23과 30, td[29]에 24와 31 삽입
}
}
} else { // 5줄이 넘어가지 않는 대다수의 달
}
두 번째로, fetch API를 다시 사용해봤다. 사실 이 과정에서 어쩌다가 모든 게 오류 없이 구현이 되긴 됐다. 되긴 됐는데, 도대체 이게 왜 되는 건지 정확히 모르겠어서 과감히 버렸다. 결과적으로 최종 코드도 이게 아닌 데다 길이도 훨씬 긴데 왜 긴지도 모르겠어서 커밋은 했지만, 블로그에는 올리지 않고 패스함.
(근데 완성 후 다시 보니까 이때 코드가 함수화를 신나게 시켜놓은 거랑(그 와중에 반복되는 긴 코드 하나는 함수화가 이상하게 안 돼서 정작 전체 코드는 길다) 처음 화면까지 동적으로 가져오느라 fetch API를 한 번 더 사용한 거 말고는, 새로 만든 최종 코드와 전체적으로 흐름이 그렇게 많이 다른 거 같진 않다. 이때나 나중이나 결국 내가 문제를 해결해나간 방향은 똑같은데 이때는 차근차근 했던 게 아니라 정리가 안 됐던 건가.)
결국 이대로는 지지부진할 뿐이란 생각이 들어서 처음부터 다시 구현을 시작해보기로 했다. 처음 구현했던 코드들이 분명히 처음부터 끝까지 내가 이해한 상태로 구현한 것들인데 오류의 원인을 찾으려고 보니까 속 시원히 왔다갔다가 안 됐다.
원인은, 줄이는 법도 제대로 모르면서 중간중간 줄이는 맛에 미리 애매하게 함수 형태로 줄여놓은 코드들과 여기저기 뭐가 뭔지 모르게 퍼져 있는 전역 변수 및 지역 변수들, 그리고 가독성이 심하게 떨어지는 변수 이름 때문인 거 같았다. 이런 점에 유의해서 백지 상태에서 처음부터 다시 시작했다.
그리고 결과는 드디어 성공...😭
그런데 이전과 비교해 if 구문의 조건식 부분과 classList 부분을 제외하면 요구 사항 해결을 위해 특별히 바꿔준 코드는 없는데 차근차근 다시 해보니까 됐다. 뭐지.
뚜렷하게 바뀐 부분은,
- 우측/좌측 화살표, 클릭 이벤트 리스너, if 구문 조건식
결국 같은 말이긴 하지만,
이걸if (currMonthLastDate > td_length - currMonthFirstDay) { if (currMonthFirstDay === 5) { } else if (currMonthFirstDay === 6) { if (currMonthLastDate === 30) { } else if (currMonthLastDate === 31) { } } } else { }
이걸로 바꿔줌
if (currMonth_firstDay + currMonth_lastDate <= td.length) { } else { }
- 특정 날짜 클릭 시, 날짜(숫자) 색깔 변경
이걸
function changeTop(num) { td[num].addEventListener('click', function clickDate () { for (let i = 0; i < currMonthLastDate; i++) { td[i].style.color = 'black'; td[num].style.color = '#ffb94f'; } }); } for (let i = 0; i < currMonthLastDate; i++) { changeTop(i); }
이걸로 바꿔줌
(버튼 클릭시 색상 변경하고 다른 버튼들은 원래 색상으로 되돌리기 참고)for (let i = 0; i < td.length; i++) { td[i].addEventListener('click', function clickDate (event) { for (let i = 0; i < td.length; i++) { td[i].classList.remove('clicked'); } event.target.classList.add('clicked'); }); }
<html>
<body>
<section>
<h1>Calendar</h1>
<div class="day-and-date">
<p class="day"></p>
<p class="date"></p>
</div>
<div class="month-and-year">
<span class="month"></span>
<span class="year"></span>
</div>
<div class="prev-table-next">
<button class="prev" type="button"><i class="fas fa-angle-double-left"></i></button>
<!-- 달력 Start -->
<table class="table">
<colgroup span="7" class="columns">
<col class="sun-line">
<col class="weekday-line" span="5">
<col class="sat-line">
</colgroup>
<thead>
<tr>
<th>SUN</th>
<th>MON</th>
<th>TUE</th>
<th>WED</th>
<th>THU</th>
<th>FRI</th>
<th>SAT</th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<!-- 달력 End -->
<button class="next" type="button"><i class="fas fa-angle-double-right"></i></button>
</div>
</section>
<script src="index.js"></script>
</body>
</html>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background-color: white;
background-repeat: no-repeat;
background-size: cover;
font-family: "Varela Round", sans-serif;
}
h1 {
font-family: "Pacifico", cursive;
text-align: center;
font-size: 72px;
margin: 50px 0;
}
.day-and-date {
text-align: center;
}
.day,
.date {
font-size: 45px;
font-weight: bold;
margin: 20px;
}
.month-and-year {
text-align: center;
margin: 50px 0 30px 0;
}
.month,
.year {
font-size: 25px;
}
.prev-table-next {
display: flex;
justify-content: center;
}
button {
border-style: none;
background: transparent;
font-size: 30px;
margin: 50px;
}
/* calendar */
.sun-line {
background-color: #ffebed;
}
.weekday-line {
background-color: #ebebeb;
}
.sat-line {
background-color: #ebf2ff;
}
th {
padding: 10px 20px;
}
td {
text-align: center;
width: 50px;
height: 25px;
padding: 10px 20px;
}
// javascript에서 특정 날짜 클릭 시, classList로 날짜(숫자) 색깔 변환을 위해 사용됨
.clicked {
color: red;
}
// html 요소 선택
const day = document.querySelector('.day');
const date = document.querySelector('.date');
const month = document.querySelector('.month');
const year = document.querySelector('.year');
const table = document.querySelector('table');
const td = document.getElementsByTagName('td');
const next = document.querySelector('.next');
const prev = document.querySelector('.prev');
// 날짜 관련 전역 변수들
const today = new Date();
const todayArray = today.toDateString().split(' ');
const currYear = today.getFullYear();
let currMonth = today.getMonth();
let currMonth_firstDay = new Date(currYear, currMonth, 1).getDay();
let currMonth_lastDate = new Date(currYear, currMonth + 1, 0).getDate();
// 오늘의 현재 요일, 날짜, 월, 연도 표기
day.innerHTML = todayArray[0];
date.innerHTML = todayArray[2];
month.innerHTML = todayArray[1];
year.innerHTML = todayArray[3];
// 현재 월의 마지막 날짜까지 달력에 표기하기
for (let i = 0; i < currMonth_lastDate; i++) {
td[i + currMonth_firstDay].innerHTML = i + 1;
}
// 특정 날짜를 클릭 했을때, 상단의 요일 & 날짜 반영하기
// 특정 날짜를 클릭 했을때, 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].addEventListener('click', function clickDate (event) {
if (td[i].innerHTML === '') {
this.removeEventListener('click', clickDate);
} else {
// 상단의 요일 & 날짜 반영하기
date.innerHTML = td[i].innerHTML;
day.innerHTML = new Date(currYear, currMonth, td[i].innerHTML).toDateString().split(' ')[0];
// 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].classList.remove('clicked');
}
event.target.classList.add('clicked');
}
}
);
}
// 📌 우측 화살표를 클릭 했을때, 상단의 월 & 연도 변경 / 날짜(숫자) 기입
next.addEventListener('click', function () {
// 필요한 테이블이 5줄이든 6줄이든, 공통 전제
currMonth = currMonth + 1;
currMonth_firstDay = new Date(currYear, currMonth, 1).getDay();
currMonth_lastDate = new Date(currYear, currMonth + 1, 0).getDate();
// 새로 테이블 만듦 (if... 5줄 / else... 6줄)
if (currMonth_firstDay + currMonth_lastDate <= td.length) { // 5줄로 커버된다면...✨
// 기존 테이블 지운 후
table.innerHTML = '';
// fetch API 이용해
fetch('table_5').then(function(response){
response.text().then(function(text){
// 새로 5줄 테이블 만들고
table.innerHTML = text;
// 날짜(숫자) 기입
for (let i = 0; i < currMonth_lastDate; i++) {
td[i + currMonth_firstDay].innerHTML = i + 1;
}
// 특정 날짜(td) 클릭 했을때, 상단의 요일 & 날짜 반영하기 + 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].addEventListener('click', function clickDate (event) {
if (td[i].innerHTML === '') {
// td 클릭 했을 때, 안에 날짜(숫자) 없으면 아무런 변화도 일어나지 않도록
this.removeEventListener('click', clickDate);
} else {
// 상단의 요일 & 날짜 반영하기
date.innerHTML = td[i].innerHTML;
day.innerHTML = new Date(currYear, currMonth, td[i].innerHTML).toDateString().split(' ')[0];
// 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].classList.remove('clicked');
}
event.target.classList.add('clicked');
}
}
);
}
})
});
} else { // 6줄이 필요하다면...✨
// 기존 테이블 지운 후
table.innerHTML = '';
// fetch API 이용해
fetch('table_6').then(function(response){
response.text().then(function(text){
// 새로 6줄 테이블 만들고
table.innerHTML = text;
// 날짜(숫자) 기입
for (let i = 0; i < currMonth_lastDate; i++) {
td[i + currMonth_firstDay].innerHTML = i + 1;
}
// 특정 날짜(td) 클릭 했을때, 상단의 요일 & 날짜 반영하기 + 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].addEventListener('click', function clickDate (event) {
if (td[i].innerHTML === '') {
// td 클릭 했을 때, 안에 날짜(숫자) 없으면 아무런 변화도 일어나지 않도록
this.removeEventListener('click', clickDate);
} else {
// 상단의 요일 & 날짜 반영하기
date.innerHTML = td[i].innerHTML;
day.innerHTML = new Date(currYear, currMonth, td[i].innerHTML).toDateString().split(' ')[0];
// 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].classList.remove('clicked');
}
event.target.classList.add('clicked');
}
}
);
}
})
});
}
// 상단의 월 & 연도 변경
month.innerHTML = new Date(currYear, currMonth).toDateString().split(' ')[1];
year.innerHTML = new Date(currYear, currMonth).toDateString().split(' ')[3];
});
// 📌 좌측 화살표를 클릭 했을때, 상단의 월 & 연도 변경 / 날짜(숫자) 기입
prev.addEventListener('click', function () {
// 필요한 테이블이 5줄이든 6줄이든, 공통 전제
currMonth = currMonth - 1;
currMonth_firstDay = new Date(currYear, currMonth, 1).getDay();
currMonth_lastDate = new Date(currYear, currMonth + 1, 0).getDate();
// 새로 테이블 만듦 (if... 5줄 / else... 6줄)
if (currMonth_firstDay + currMonth_lastDate <= td.length) { // 5줄로 커버된다면...✨
// 기존 테이블 지운 후
table.innerHTML = '';
// fetch API 이용해
fetch('table_5').then(function(response){
response.text().then(function(text){
// 새로 5줄 테이블 만들고
table.innerHTML = text;
// 날짜(숫자) 기입
for (let i = 0; i < currMonth_lastDate; i++) {
td[i + currMonth_firstDay].innerHTML = i + 1;
}
// 특정 날짜(td) 클릭 했을때, 상단의 요일 & 날짜 반영하기 + 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].addEventListener('click', function clickDate (event) {
if (td[i].innerHTML === '') {
// td 클릭 했을 때, 안에 날짜(숫자) 없으면 아무런 변화도 일어나지 않도록
this.removeEventListener('click', clickDate);
} else {
// 상단의 요일 & 날짜 반영하기
date.innerHTML = td[i].innerHTML;
day.innerHTML = new Date(currYear, currMonth, td[i].innerHTML).toDateString().split(' ')[0];
// 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].classList.remove('clicked');
}
event.target.classList.add('clicked');
}
}
);
}
})
});
} else { // 6줄이 필요하다면...✨
// 기존 테이블 지운 후
table.innerHTML = '';
// fetch API 이용해
fetch('table_6').then(function(response){
response.text().then(function(text){
// 새로 6줄 테이블 만들고
table.innerHTML = text;
// 날짜(숫자) 기입
for (let i = 0; i < currMonth_lastDate; i++) {
td[i + currMonth_firstDay].innerHTML = i + 1;
}
// 특정 날짜(td) 클릭 했을때, 상단의 요일 & 날짜 반영하기 + 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].addEventListener('click', function clickDate (event) {
if (td[i].innerHTML === '') {
// td 클릭 했을 때, 안에 날짜(숫자) 없으면 아무런 변화도 일어나지 않도록
this.removeEventListener('click', clickDate);
} else {
// 상단의 요일 & 날짜 반영하기
date.innerHTML = td[i].innerHTML;
day.innerHTML = new Date(currYear, currMonth, td[i].innerHTML).toDateString().split(' ')[0];
// 날짜(숫자) 색깔 바꾸기
for (let i = 0; i < td.length; i++) {
td[i].classList.remove('clicked');
}
event.target.classList.add('clicked');
}
}
);
}
})
});
}
// 상단의 월 & 연도 변경
month.innerHTML = new Date(currYear, currMonth).toDateString().split(' ')[1];
year.innerHTML = new Date(currYear, currMonth).toDateString().split(' ')[3];
});
// html 요소 선택
const day = document.querySelector('.day');
const date = document.querySelector('.date');
const month = document.querySelector('.month');
const year = document.querySelector('.year');
const table = document.querySelector('table');
const td = document.getElementsByTagName('td');
const next = document.querySelector('.next');
const prev = document.querySelector('.prev');
// 날짜 관련 전역 변수들
const today = new Date();
const todayArray = today.toDateString().split(' ');
const currYear = today.getFullYear();
let currMonth = today.getMonth();
let currMonth_firstDay = new Date(currYear, currMonth, 1).getDay();
let currMonth_lastDate = new Date(currYear, currMonth + 1, 0).getDate();
// 오늘의 현재 요일, 날짜, 월, 연도 표기
day.innerHTML = todayArray[0];
date.innerHTML = todayArray[2];
month.innerHTML = todayArray[1];
year.innerHTML = todayArray[3];
// 현재 월의 마지막 날짜까지 달력에 표기하기
function insertDate () {
for (let i = 0; i < currMonth_lastDate; i++) {
td[i + currMonth_firstDay].innerHTML = i + 1;
}
}
insertDate();
// 특정 날짜 클릭
function clickDate () {
for (let i = 0; i < td.length; i++) {
td[i].addEventListener('click', function clickDate (event) {
if (td[i].innerHTML === '') {
this.removeEventListener('click', clickDate);
} else {
date.innerHTML = td[i].innerHTML;
day.innerHTML = new Date(currYear, currMonth, td[i].innerHTML).toDateString().split(' ')[0];
for (let i = 0; i < td.length; i++) {
td[i].classList.remove('clicked');
}
event.target.classList.add('clicked');
}
}
);
}
}
clickDate();
// fetch API
function fetchPage (fileName) {
fetch(fileName).then(function(response){
response.text().then(function(text){
table.innerHTML = text;
insertDate();
clickDate();
})
});
}
// 좌우 화살표 클릭
function clickBtn (type, num) {
type.addEventListener('click', function () {
currMonth = currMonth + num;
currMonth_firstDay = new Date(currYear, currMonth, 1).getDay();
currMonth_lastDate = new Date(currYear, currMonth + 1, 0).getDate();
if (currMonth_firstDay + currMonth_lastDate <= td.length) {
table.innerHTML = '';
fetchPage('table_5');
} else {
table.innerHTML = '';
fetchPage('table_6')
}
month.innerHTML = new Date(currYear, currMonth).toDateString().split(' ')[1];
year.innerHTML = new Date(currYear, currMonth).toDateString().split(' ')[3];
});
}
clickBtn(next, 1);
clickBtn(prev, -1);
일단 드디어 끝났다. 이번 실습을 하면서도 역시나 달력이란 키워드를 넣고는 단 한 번도 검색해보지 않았는데 어제부터 위 문제가 해결이 안 돼서 오늘 아침에 잠깐 흐린 눈으로 검색을 했었다. 코드를 검색한 게 아니라 다른 사람들은 다들 쉽게 완성을 하는 건가를 봤는데 흐린 눈이라 그런진 몰라도 다 너무 쉽게 완성을 하는 거 같았다. 그동안 내 딴에는 그래도 짧지만 열심히 공부해왔다고 생각했는데 나만 못하는 건가 싶어서 잠깐 우울했음. 그래도 극복하고 결국 해냈다.
누군가 보기엔 우습기 짝이 없겠지만, 여태까지 내가 만들어본 것 중 가장 길고 복잡한 코드였다. 그래서 코드 상태는 엉망일지 몰라도 일단 오류 없이 실행이 된다는 거 자체가 뿌듯하다. 다른 짧았던 실습들은 다시 하려고 하면 막히는 부분이 있을 거 같은데 이건 오히려 어렵지 않게 다시 할 수 있을 거 같다.
이번 실습을 하면서 어느 순간 느꼈던 건 이제 for 반복문
과 if 구문
을 사용하면서 전처럼 주춤하지는 않는다는 사실이었다. 특히 불과 열흘 전까지만 해도 carousel을 구현하면서 내가 for 반복문을 잘 모른다는 걸 알고 이론과 실습의 격차를 뼈저리게 느꼈었는데 이번엔 적어도 for 반복문 때문에 막힌 적은 없었던 거 같다. 기본 of 기본 of 기본이지만, 이제야 그 기본이 살짝이나마 익숙해진 듯하다.
리팩토링
에 대해서 어줍잖게 아는 상태로는 사용하지 말자고 다짐했다. 이틀 전에 생활코딩 ajax 강의를 들으면서 마지막에 함수화가 짧게 소개되는 걸 보고 인상깊어서 이번에 시도해봤던 건데 제대로 쓸 줄도 모르면서 그때그때 써 놓으니까 뒤에 가서 앞의 오류를 찾는 게 힘들었다. 함수화를 해서 코드가 쑥쑥 줄어드는 걸 보는 건 재밌는데 반대로 거슬러서 거리낌없이 해석해나가는 게 아직은 어렵다. 하려면 아예 마지막에 해야겠다.
이번 달력 구현을 마지막으로, 1차로 목표했던 사전 학습이 모두 마무리됐다.
총 40일 정도가 걸린 거 같다. 딱 하루만 빼고 매일같이 최소 12 ~ 14시간까지 공부를 했는데 돌이켜보면 40일이 정말 훅 간 거 같다. 여전히 어려운 것 투성이지만, 그래도 지금에 와서 그 중 아주 일부라도 오롯이 내 것이 되어 있는 게 신기하다. 앞으로도 지금까지처럼 내 스스로가 지치지 않았으면 좋겠다. 지쳐서도 안되지만 부디 계속 재밌었으면. 😁
내일은 그동안 블로그에 정리해둔 TIL들을 잠깐 훑어보는 시간을 가져야겠다. 꼼꼼히 다 보기도 무리일 거고 어차피 실습을 해야 비로소 의미가 있다는 걸 이젠 알지만, 그래도 전체적으로 그간 배운 게 뭔지 머릿속에 크게 정리하는 시간을 가지면 좋을 거 같다.
앞으로 어떻게 공부해 나가야 할지도 계획을 좀 더 구체적으로 세워야겠다. 원래 오늘 하려고 했는데 이미 오늘이 어제가 되어버린 관계로 어제오늘은 이만...아무튼 이렇게 달력 구현도 완료 ❕❕