์ด์ ๊ธ์์ ๋ฌ๋ ฅ์ ๋ง๋ค๊ธฐ ์ํ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์์ต๋๋ค. ์ด๋ฒ์๋ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ์ฌ ๋ ๊ฐ์ง ์ข ๋ฅ์ ๋ฌ๋ ฅ์ ๋ง๋ค์ด ๋ด ๋๋ค. ํ๋๋ Schedule์ ๋๋ค. Schedule์ ๋ฌ๋ ฅ์์ ํน์ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌ๋ ฅ์ ํด๋นํฉ๋๋ค.
1. ๊ตฌ๊ธ ์บ๋ฆฐ๋(์ผ์ ์ ํ์ธํ ์ ์๋ค.)
2. ๊ฐ๊ณ๋ถ(์ง์ถํ ๊ธ์ก์ ํ์ธํ ์ ์๋ค.)
์ ๋ฌ๋ ฅ์ ๋ชจ๋ ํน์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ ๋ฌ๋ ฅ์ ๋๋ค. ๋ ๋ค๋ฅธ ๋ฌ๋ ฅ์ Date Picker์ ๋๋ค. ์ด๋ฆ ๊ทธ๋๋ก ๋ ์ง๋ฅผ ์ ํํ ์ ์๋ ๋ฌ๋ ฅ์ ๋๋ค. ์ด๋ html์ input ํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํํ ์๋ ์๋๋ฐ, ์ปค์คํฌ์ ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์ํ๋ UI๋ฅผ ๋ง๋ค๊ธฐ ์ํด์ ์ฒ์๋ถํฐ ์ค์ค๋ก ๋ง๋๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ค.
์ด๋ฒ ์ฑํฐ์๋ ์ฝ๋๋์ด ๋ง์ ์ธ์ธํ ์ฝ๋์ ๋ํ ์ค๋ช ์ ํ์ง ์์ต๋๋ค. ์ ๋ฐ์ ์ธ ๋๋ ๋ฐ ์ปจ์ ๋ง ์ง๊ณ ๋์ด๊ฐ์๋ฉด ๋ฉ๋๋ค.
1. Schedule, Date Picker ๋ฒํผ ๊ตฌํํ๊ธฐ
๋ณธ๊ฒฉ์ ์ธ ๋ฌ๋ ฅ UI๋ฅผ ๋ง๋ค๊ธฐ์ ์์, ๊ธฐ๋ณธ์ ์ธ html, css ๋ผ๋๋ฅผ ๋ง๋ค๊ณ ๋ ๊ฐ์ ๋ฌ๋ ฅ์ ์ ํํ ์ ์๋ ๋ฒํผ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
1-1. index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="src/css/index.css" />
<title>Vanilla Calendar</title>
</head>
<body>
<div class="button-container"> // ๋ฒํผ ์ปจํ
์ด๋
<button class="schedule-button button">Schedule</button>
<button class="date-picker-button button">Date Picker</button>
</div>
<div class="calendar"></div> // ์บ๋ฆฐ๋๊ฐ ๋๋๋ง ๋ ์์น
<script type="module" src="/src/main.ts"></script>
</body>
</html>
button-container์๋ Schedule, Date Picker ๋ฌ๋ ฅ์ ์ ํํ ์ ์๋ ๋ ๊ฐ์ ๋ฒํผ์ด ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ calendar๊ฐ ๋๋๋ง ๋ ์์น๋ฅผ ์ ํด์ค๋๋ค.
ts์ ์ง์ ์ ์ด ๋๋ main.ts๋ script ํ๊ทธ๋ฅผ ํตํด ๋ถ๋ฌ์ต๋๋ค. ํ์ง๋ง ์์ง main.ts์๋ ์๋ฌด๋ฐ ์ฝ๋๊ฐ ์์ต๋๋ค.
1-2. index.css
@import url('./schedule.css');
@import url('./datePicker.css');
@import url('./common.css');
@import url('./button.css');
* {
margin: 0;
padding: 0;
font: inherit;
color: inherit;
user-select: none;
}
*,
:after,
:before {
box-sizing: border-box;
flex-shrink: 0;
}
ol,
ul {
list-style: none;
margin: 0px;
padding: 0px;
}
body {
background-color: #fafafa;
}
.calendar {
max-width: 700px;
margin: 20px auto;
}
์์ผ๋ก ์ฌ์ฉํ๊ฒ ๋ css ํ์ผ์ import์ ํ๊ณ ์ ์ฒด์ ์ผ๋ก ์ ์ฉ๋๋ ์คํ์ผ์ ์์ฑํฉ๋๋ค. reset style์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค. ๋ํ index.html์์ ์์ฑํ calendar์ ์คํ์ผ๋ ํจ๊ป ์์ฑํฉ๋๋ค.
1-3. button.css
.button-container {
position: fixed;
right: 20px;
bottom: 20px;
display: flex;
justify-content: center;
gap: 10px;
}
.button {
background-color: #3b82f6;
color: rgb(255, 255, 255);
padding: 16px 40px;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.2s ease;
}
.button:hover {
background-color: #2563eb;
}
๋ฒํผ์ ์์น fixed๋ก ํ์ฌ ์ฐ์ธก ํ๋จ์ ์์น์ํค์๊ณ ์คํ์ผ์ ์ ํ๋๋ค.
1-4. ๊ฒฐ๊ณผ
Schedule, Date Picker ๋ฒํผ์ ๋ง๋ค์์ต๋๋ค.
๋ค์์ ํด๋น ์์ ์ ๋ํ commit์ ๋๋ค.
2. Schedule class
main.ts์ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ , Schedule class๋ฅผ ๋จผ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. Schedule class์์๋ ๋ฌ๋ ฅ์ ๋ง๋ค๊ธฐ ์ํ ๋ฐ์ดํฐ๋ฅผ Calendar ์ธ์คํด์ค์์ ๊ฐ์ ธ์ค๊ณ ์ด๋ฅผ ๋ฐํ์ผ๋ก tmplate๋ฅผ ๋ง๋ญ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ฅผ render ํจ์๋ก ๊ฐ์ธ main.ts์์ ์ฌ์ฉํ ์ ์๋๋ก ํฉ๋๋ค.
์ ์ฒด์ ์ธ ์ฝ๋๋ฅผ ๋จผ์ ๋ณด๊ณ ํ๋ํ๋ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ฌ๊ธฐ์๋ถํฐ๋ css ์ฝ๋์ ๋ํด์๋ ์ค๋ช ํ์ง ์๊ฒ ์ต๋๋ค. ์์ค์ฝ๋๊ฐ ๋ณด๊ณ ์ถ์ ๋ถ๋ค์ ๋ง์ง๋ง์ github repo ์ฃผ์๋ฅผ ๋จ๊ธธ ํ ๋ ์ฐธ๊ณ ๋ถํ๋๋ฆฝ๋๋ค.
import Calendar from './Calendar';
import { $ } from './dom';
class Schedule {
#calendar;
constructor() {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
this.#calendar = new Calendar(year, month);
}
render = () => {
const containerTemplate = `
<h1 class="title">Schedule Calendar</h1>
<div class="schedule-container"></div>
`;
$('.calendar').innerHTML = containerTemplate;
this.renderCalendar();
};
private renderCalendar = () => {
const getDayOfWeekClassName = (dayOfWeek: number) => {
if (dayOfWeek === 0) return 'sunday';
if (dayOfWeek === 6) return 'saturday';
return 'weekday';
};
const yearMonthTemplate = `
<div class="schedule-year-month">
${this.#calendar.getYear()}๋
${this.#calendar.getMonth()}์
</div>
`;
const calendarTemplate = `
<ul class="schedule-day-of-weeks">
${['์ผ', '์', 'ํ', '์', '๋ชฉ', '๊ธ', 'ํ ']
.map(
(dayOfWeek, index) =>
`<div class="schedule-day-of-week ${getDayOfWeekClassName(
index
)}">${dayOfWeek}</div>`
)
.join('')}
</ul>
<ul class="schedule-calendar">
${this.#calendar
.getCalendarStorage()
.map(
({ day, state, date, dayOfWeek }) =>
`<li class="schedule-calendar-item">
<span class="schedule-calendar-day ${`${state}-month`} ${getDayOfWeekClassName(
dayOfWeek
)} ${this.#calendar.isToday(date) && 'today'}">${day}</span>
</li>`
)
.join('')}
</ul>
`;
$('.schedule-container').innerHTML = yearMonthTemplate + calendarTemplate;
};
}
export default Schedule;
2-1. constructor
constructor() {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
this.#calendar = new Calendar(year, month);
}
Schedule class์์์ constructor์์๋ ์ค๋ ๋ ์ง๋ฅผ ๊ฐ์ ธ์ต๋๋ค.(today) ์ด๋ฅผ ๋ฐํ์ผ๋ก ํ์ฌ ๋ ๋์ ๋ฌ์ ๊ณ์ฐํ๊ณ Calendar ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ธฐ ์ํ ์ธ์๋ก ์ ๋ฌํฉ๋๋ค. ์ด๋ ๊ฒ ์์ฑํ Calendar ์ธ์คํด์ค๋ private filed์ธ #calendar์ ํ ๋นํฉ๋๋ค.
2-2. render
render = () => {
const containerTemplate = `
<h1 class="title">Schedule Calendar</h1>
<div class="schedule-container"></div>
`;
$('.calendar').innerHTML = containerTemplate;
this.renderCalendar();
};
render ๋ฉ์๋๋ Schedule class ์ธ๋ถ์์ ํธ์ถํ ์ ์์ต๋๋ค.
์ด๊ณณ์์๋ containerTemplate๋ฅผ ๋ง๋ญ๋๋ค. ์ด๋ ๋ฌ๋ ฅ์ ์ ๋ชฉ๊ณผ Schedule Calendar๊ฐ ๋ ๋๋ง ๋ schedule-container์ ๋ง๋ค๋ฉฐ index.html์์ ์์ฑํ calendar์ ๋ด๋ถ์ innerHTML์ ํตํด ์ฝ์ ๋ฉ๋๋ค.
์ด์ด์ renderCalendar ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ์ด๋ฅผ ๋ถ๋ฆฌํ ์ด์ ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. ํ๋์ ๋ฉ์๋๊ฐ ๋ง์ ์ญํ ์ ํ๊ณ ์๊ณ ์ฝ๋์ ๊ธธ์ด ๊ฐ๋ ์ฑ์ด ๋จ์ด์ง๋๋ค.
2. ๋ , ์์ด ๋ฐ๋ ๊ฒฝ์ฐ ์๋กญ๊ฒ ๋ ๋๋ง์ด ๋๋ ๋ถ๋ถ์ ๋ถ๋ฆฌํฉ๋๋ค.
3-2. renderCalendar
private renderCalendar = () => {
const getDayOfWeekClassName = (dayOfWeek: number) => {
if (dayOfWeek === 0) return 'sunday';
if (dayOfWeek === 6) return 'saturday';
return 'weekday';
};
const yearMonthTemplate = `
<div class="schedule-year-month">
${this.#calendar.getYear()}๋
${this.#calendar.getMonth()}์
</div>
`;
const calendarTemplate = `
<ul class="schedule-day-of-weeks">
${['์ผ', '์', 'ํ', '์', '๋ชฉ', '๊ธ', 'ํ ']
.map(
(dayOfWeek, index) =>
`<div class="schedule-day-of-week ${getDayOfWeekClassName(
index
)}">${dayOfWeek}</div>`
)
.join('')}
</ul>
<ul class="schedule-calendar">
${this.#calendar
.getCalendarStorage()
.map(
({ day, state, date, dayOfWeek }) =>
`<li class="schedule-calendar-item">
<span class="schedule-calendar-day ${`${state}-month`} ${getDayOfWeekClassName(
dayOfWeek
)} ${this.#calendar.isToday(date) && 'today'}">${day}</span>
</li>`
)
.join('')}
</ul>
`;
$('.schedule-container').innerHTML = yearMonthTemplate + calendarTemplate;
};
๋ถ๋ฆฌ๋ฅผ ํ์์๋ ์ฝ๋์ ๊ธธ์ด๊ฐ ๋งค์ฐ ๊น๋๋ค. ํ์ง๋ง ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ํ ์ฝ๋๋ง ์์ ๋ฟ ๋ณต์กํ ๋ก์ง์ ์์ต๋๋ค. ํ๋์ฉ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ getDayOfWeekClassName ํจ์์ ๋๋ค. ์์ผ(์ธ๋ฑ์ค)๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ํ์ฌ ์์ผ์ด ํ ์์ผ, ์ผ์์ผ ๊ทธ๋ฆฌ๊ณ ํ์ผ์ธ์ง๋ฅผ ๋ฐํํฉ๋๋ค. ๋ฐํ๋ ๊ฐ์ class name์ผ๋ก ์ฌ์ฉ๋๋๋ฐ ์ด๋ ํ ์์ผ, ์ผ์์ผ, ํ์ผ์ ๋ฐ๋ผ ๋ค๋ฅธ color๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ํจ์ ๋๋ค.
๋ค์์ yearMonthTemplate์ ๋๋ค. ์ด๋ฆ ๊ทธ๋๋ก ํ์ฌ ๋ฌ๋ ฅ์ ๋ , ์์ ๋ด์ template์ ๋๋ค. Calendar ์ธ์คํด์ค์ getYear() ๋ฉ์๋, getMonth() ๋ฉ์๋๋ฅผ ํตํด ํ์ฌ ๋ฌ๋ ฅ์ ๋ , ์์ ๊ฐ์ ธ์ต๋๋ค.
- this.#calendar.getYear(): ํ์ฌ ๋ฌ๋ ฅ์ ๋
- this.#calendar.getMonth(): ํ์ฌ ๋ฌ๋ ฅ์ ์
์ด์ด์ calendarTemplate์ ๋๋ค. ๋ฌ๋ ฅ์ ๊ทธ๋ฆฌ๊ธฐ ์ํด ๊ฐ์ฅ ํต์ฌ์ด ๋๋ฉฐ Schedule class์์ ๊ฐ์ฅ ์ค์ํ ์ญํ ์ ๋ด๋นํ๊ณ ์์ต๋๋ค.
๋จผ์ ๋ฌ๋ ฅ ์๋จ์ ์์ผ(ํ ~์ผ)์ ๊ทธ๋ฆฝ๋๋ค. ์ด์ด์ ์ด์ ์ฑํฐ์์ ๋ง๋ ๋ฌ๋ ฅ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ์ฌ ๋ฌ๋ ฅ template๋ฅผ ๋ง๋ญ๋๋ค. ์ด๋ ๋ฌ๋ ฅ ๋ฐ์ดํฐ๋ Calendar ์ธ์คํด์ค์ getCalendarStorage ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ ธ์ต๋๋ค.
- this.#calendar.getCalendarStorage(): ํ์ฌ ๋ฌ๋ ฅ์ ๋ฐ์ดํฐ
calendarStroage์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
1. day: ์ผ
2. state: ์ด์ , ํ์ฌ, ๋ค์ ๋ฌ์ ๋ํ ์ ๋ณด(perv | cur | next)
3. date: ํด๋น ๋ ์ ๋ํ Date ๊ฐ์ฒด
4. dayOfWeek: ์์ผ(0~6)
์ด๋ฅผ ํ ๋๋ก ์ํ๋ class name์ ์ ํ ์ ์๊ณ ์ ๋ณด๋ฅผ ํ๋ฉด์ ๋ํ๋ผ ์ ์์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก yearMonthTemplate๊ณผ calendarTemplate๋ฅผ render ๋ฉ์๋์์ ์์ฑํ schedule-container์ innerHTML์ ํตํด ์ฝ์ ํฉ๋๋ค.
3-3. ๋ง๋ฌด๋ฆฌ
Sehedule class์ ๋ํด ์ดํด๋ดค์ต๋๋ค. Calendar ์ธ์คํด์ค ํตํด ๊ฐ์ ธ์จ calendarStorage ๋๋ถ์ ๋ณต์กํ ๋ก์ง ์์ด template๋ฅผ ๋ง๋ค ์ ์์์ต๋๋ค.
ํ์ง๋ง ์์ง main.ts์์ ์์ ์ ํ์ง ์์ ํ๋ฉด์ Schedule Calendar๊ฐ ๋ ๋๋ง์ด ๋์ง ์์ต๋๋ค. ๋ฐ๋ก ์ด์ด์ main.ts์ ์ฝ๋๋ฅผ ์์ฑํ์ฌ Schedule Calendar๋ฅผ ํ๋ฉด์ ๋ ๋๋ง์ ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ค์์ ์ด๋ฒ ์์ ์ ๋ํ commit์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฏธ์ณ ๋ค๋ฃจ์ง ๋ชปํ ์์ค์ฝ๋์ ๋ํ github ์ฃผ์์ ๋๋ค.
๐ common.css๋ก Schedule Calendar์ Date Picker Calendar๊ฐ ๊ณตํต์ผ๋ก ์ฌ์ฉ๋๋ ์คํ์ผ์ด ์์ฑ๋ ํ์ผ์ ๋๋ค.
https://github.com/nlom0218/vanilla-calendar/blob/main/src/css/common.css
๐ schedule.css๋ก Schedule Calendar์์ ์ฌ์ฉ๋๋ ์คํ์ผ์ด ์์ฑ๋ ํ์ผ์ ๋๋ค.
https://github.com/nlom0218/vanilla-calendar/blob/main/src/css/schedule.css
๐ dom.ts๋ก element๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํ $ ํจ์๊ฐ ์ ์ธ๋ ํ์ผ์ ๋๋ค.
https://github.com/nlom0218/vanilla-calendar/blob/main/src/ts/dom.ts
3. main.ts - Schedule Calendar ๋ ๋๋ง
2์์ ๋ง๋ Schedule class๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ฉด์ Schedule Calendar์ ๋ ๋๋ง์ ํ๊ฒ ์ต๋๋ค. ํ์ง๋ง ์์ง ๋ฌ๋ ฅ์ด ํ๋๋ฐ์ ์๊ธฐ ๋๋ฌธ์ ๋ฒํผ์ ๋ํ ์ด๋ฒคํธ๋ ๊ตฌํํ์ง ์์์ต๋๋ค.
import Schedule from './ts/Schedule';
class App {
#schedule;
constructor() {
this.#schedule = new Schedule();
}
init() {
this.#schedule.render();
}
}
const app = new App();
app.init();
App class๊ฐ ์๊ณ ์ธ์คํด์ค๋ฅผ ์์ฑํ ํ init ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค. ์ธ์คํด์ค๋ฅผ ์์ฑํ ์์ ์ Schedule ์ธ์คํด์ค๊ฐ ์์ฑ๋์ด private filed์ธ #schedule์ ํ ๋น๋ฉ๋๋ค. ์ดํ init ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ Schedule ์ธ์คํด์ค์ render ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค.
- this.#schedule.render(): Schedule Calendar๊ฐ ํ๋ฉด์ ๊ทธ๋ ค์ง๋๋ค.
๋ค์์ด ํด๋น ์์ ์ ๋ํ commit์ ๋๋ค.
4. DatePickerCalendar class
์ด์ด์ ๋ฌ๋ ฅ์ ๋ ์ง๋ฅผ ์ ํํ ์ ์๋ Date Picker Calendar์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ์ํด 2๊ฐ์ ํด๋์ค๋ฅผ ๋ง๋ค์ด ๋ณด๋ ค๊ณ ํฉ๋๋ค.
1. DatePickerCalendar: Date Picker Calendar์ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋ ํด๋์ค(Calendar ํด๋์ค๋ฅผ ์์๋ฐ์ต๋๋ค.)
2. DatePicker: ์ฌ์ฉ์์ ์ํธ์์ฉํ๊ฒ ๋ ํด๋์ค(ํ๋ฉด์ ๋ฌ๋ ฅ์ ๋ ๋๋งํ๊ณ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์กด์ฌํฉ๋๋ค.)
์ด ์ค ๋จผ์ DatePickerCalendar class์ ๋ง๋ค์ด Date Picker Calendar์ ํ์ํ ๊ธฐ๋ฅ ์ถ๊ฐ ๊ตฌํํ๊ฒ ์ต๋๋ค.
ํ์ฌ ๋ ์ค๋ฅด๋ ํ์ํ ๊ธฐ๋ฅ์ ์์์ผ๊ณผ ๋ง์ง๋ง์ผ์ ์ ํํ๋ ๊ธฐ๋ฅ์ ๋๋ค. ์ด ๊ธฐ๋ฅ์ ๋ฐํ์ผ๋ก ๋ค์ํ ๋ค์๊ณผ ๊ฐ์ ํ์๋ ๊ธฐ๋ฅ์ด ์กด์ฌํฉ๋๋ค.
1. ํน์ ๋ ์ด ์์์ผ์ธ์ง?
2. ํน์ ๋ ์ด ๋ง์ง๋ง์ผ์ธ์ง?
3. ํน์ ๋ ์ด ์์์ผ๊ณผ ๋ง์ง๋ง์ผ ์ฌ์ด์ธ์ง?
์ด๋ฅผ ๊ตฌํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค. ์ฐ์ ์ ์ฒด์ ์ธ ์ฝ๋์ ๋๋ค. ์ดํ ํ๋์ฉ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
// utils/format.ts
const format = {
date: (date: Date, delimiter?: '-' | '.') => {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
if (!delimiter) return `${year}๋
${month}์ ${day}์ผ`;
return `${year}${delimiter}${month < 10 ? `0${month}` : month}${delimiter}${
day < 10 ? `0${day}` : day
}`;
},
};
export default format;
// ts/DatePickerCalendar.ts
import format from '../utils/format';
import Calendar from './Calendar';
class DatePickerCalendar extends Calendar {
#startDate: Date | null = null;
#endDate: Date | null = null;
constructor(year: number, month: number) {
super(year, month);
}
init = () => {
this.#startDate = null;
this.#endDate = null;
};
setDate = (date: Date) => {
if (!this.#startDate) {
this.#startDate = date;
return;
}
if (!this.#endDate && date > this.#startDate) {
this.#endDate = date;
return;
}
if (!this.#endDate) {
this.#endDate = this.#startDate;
this.#startDate = date;
return;
}
if (this.#startDate && this.#endDate) {
this.#startDate = date;
this.#endDate = null;
return;
}
};
getStartDate = () => this.#startDate;
getEndDate = () => this.#endDate;
isEqualStartDate = (date: Date) => {
if (!this.#startDate) return false;
const startDate = format.date(this.#startDate);
const inputDate = format.date(date);
return startDate === inputDate;
};
isEqualEndDate = (date: Date) => {
if (!this.#endDate) return false;
const endDate = format.date(this.#endDate);
const inputDate = format.date(date);
return endDate === inputDate;
};
isIncludedDate = (date: Date) => {
if (!this.#startDate || !this.#endDate) return;
return date < this.#endDate && date > this.#startDate;
};
}
export default DatePickerCalendar;
4-1. format ๊ฐ์ฒด
const format = {
date: (date: Date, delimiter?: '-' | '.') => {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
if (!delimiter) return `${year}๋
${month}์ ${day}์ผ`;
return `${year}${delimiter}${month < 10 ? `0${month}` : month}${delimiter}${
day < 10 ? `0${day}` : day
}`;
},
};
๋จผ์ format ๊ฐ์ฒด์ ๋๋ค. format ๊ฐ์ฒด์ date ํจ์๋ Date ๊ฐ์ฒด๋ฅผ ๋ฐ์ ์ํ๋ ํํ์ ๋ ์ง ํ์์ผ๋ก ๋ณํ ํ ๋ฐํํ๋ ์ญํ ์ ํฉ๋๋ค. ๋๋ฒ์งธ ๋งค๊ฐ๋ณ์์ธ delimiter๊ฐ ์์ผ๋ฉด yyyy๋ m์d์ผ ํ์์ผ๋ก ๋ณํํ์ฌ ๋ฐํํ๊ณ delimiter๊ฐ ์๋ค๋ฉด ๋ ์์ผ ์ฌ์ด์ ํด๋น delimiter๋ฅผ ์ถ๊ฐํ์ฌ ๋ณํํ๊ณ ๋ฐํํฉ๋๋ค.
๋ค์์ผ๋ก DatePickerCalendar class๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
4-2. ์์ ๋ฐ constructor
class DatePickerCalendar extends Calendar {
#startDate: Date | null = null;
#endDate: Date | null = null;
constructor(year: number, month: number) {
super(year, month);
}
// ...
}
DatePickerCalendar๋ ๊ธฐ๋ณธ์ ์ผ๋ก Calendar์ ๋ชจ๋ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ฆ, DatePickerCalendar๋ Calendar์ ํ์ฅ๋ ๋ฒ์ ์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค.
๋๋ฌธ์ extends Calendar๋ฅผ ํตํด Calendar๋ฅผ ์์๋ฐ์ต๋๋ค.
4-3. init
init = () => {
this.#startDate = null;
this.#endDate = null;
};
init ๋ฉ์๋๋ DatePickerCalendar์ private filed์ธ #startDate์ #endDate์ null๋ก ์ฌํ ๋นํ์ฌ ์ด๊ธฐํํ๋ ์ญํ ์ ํฉ๋๋ค.
4-4. setDate
setDate = (date: Date) => {
if (!this.#startDate) {
this.#startDate = date;
return;
}
if (!this.#endDate && date > this.#startDate) {
this.#endDate = date;
return;
}
if (!this.#endDate) {
this.#endDate = this.#startDate;
this.#startDate = date;
return;
}
if (this.#startDate && this.#endDate) {
this.#startDate = date;
this.#endDate = null;
return;
}
};
setDate ๋ฉ์๋๋ Date ๊ฐ์ฒด๋ฅผ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ #startDate ๋๋ #endDate์ Date ๊ฐ์ฒด๋ฅผ ์ฌํ ๋นํ๋ ์ญํ ์ ํฉ๋๋ค.
์ฌ๊ธฐ์๋ ๋ค์ํ ์กฐ๊ฑด๋ฌธ์ด ์์ต๋๋ค.
1. #startDate๊ฐ ์๋ค๋ฉด #startDate์ Date ๊ฐ์ฒด๋ฅผ ์ฌํ ๋นํฉ๋๋ค.
2. #endDate๊ฐ ์๊ณ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ Date ๊ฐ์ฒด๊ฐ #startDate ๋ณด๋ค ์ดํ์ ๋ ์ง๋ผ๋ฉด #endDate์ Date ๊ฐ์ฒด๋ฅผ ์ฌํ ๋นํฉ๋๋ค.
3. #endDate๊ฐ ์๊ณ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ Date ๊ฐ์ฒด๊ฐ #startDate ๋ณด๋ค ์ด์ ์ ๋ ์ง๋ผ๋ฉด #endDate์ #startDate๋ฅผ ์ฌํ ๋นํ๊ณ #endDate์๋ Date ๊ฐ์ฒด๋ฅผ ์ฌํ ๋นํฉ๋๋ค. ์ด๋ฌํ ์ด์ ๋ ์์์ผ๊ณผ ๋ง์ง๋ง์ผ์ ์๋ก ๋ฐ๊ฟ์ผ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
4. #startDate, #endDate๊ฐ ๋ชจ๋ ์๋ค๋ฉด ๋ค์ ๋ ์ง๋ฅผ ์ ํํ๋ ์ํฉ์ด๋ฏ๋ก #startDate์๋ Date ๊ฐ์ฒด, #endDate์๋ null๋ฅผ ์ฌํ ๋นํฉ๋๋ค.
4-5. getStartDate, getEndDate
getStartDate = () => this.#startDate;
getEndDate = () => this.#endDate;
DatePickerCalendar์ private filed์ธ #startDate์ #endDate๋ฅผ ์ธ๋ถ๋ก ์ ๋ฌํ๊ธฐ ์ํ ๋ฉ์๋์ ๋๋ค.
4-6. isEqualStartDate, isEqualEndDate
isEqualStartDate = (date: Date) => {
if (!this.#startDate) return false;
const startDate = format.date(this.#startDate);
const inputDate = format.date(date);
return startDate === inputDate;
};
isEqualEndDate = (date: Date) => {
if (!this.#endDate) return false;
const endDate = format.date(this.#endDate);
const inputDate = format.date(date);
return endDate === inputDate;
};
isEqualStartDate ๋ฉ์๋์ isEqualEndDate ๋ฉ์๋๋ ๊ฐ๊ฐ ๋ฌ๋ ฅ์ ๋ ์ง(๋งค๊ฐ๋ณ์์ธ date)๊ฐ ์์์ผ๊ณผ ๋ง์ง๋ง์ผ๊ณผ ๊ฐ์์ง๋ฅผ ํ๋จํ๊ณ ํ๋จ ๊ฒฐ๊ณผ๋ฅผ boolean์ผ๋ก ๋ฐํํ๋ ์ญํ ์ ํฉ๋๋ค.
์ด๋, format.date ํจ์๋ฅผ ์ฌ์ฉํ์ฌ Date ๊ฐ์ฒด๋ฅผ ๋ฌธ์์ด๋ก ๋ณํ ํ ์๋ก ๊ฐ์์ง ๋น๊ตํฉ๋๋ค. ๋ฌธ์์ด๋ก ๋ณํ ํ ๋น๊ตํ๋ ์ด์ ๋ Date ๊ฐ์ฒด๋ก ์๋ก ๊ฐ์์ง๋ฅผ ํ๋จํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
4-7. isIncludedDate
isIncludedDate = (date: Date) => {
if (!this.#startDate || !this.#endDate) return;
return date < this.#endDate && date > this.#startDate;
};
isIncludedDate ๋ฉ์๋๋ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ Date ๊ฐ์ฒด๊ฐ #startDate์ #endDate ์ฌ์ด์ ๊ฐ์ธ์ง ํ๋จํ๊ณ ์ด๋ฅผ boolean์ผ๋ก ๋ฐํํ๋ ์ญํ ์ ํฉ๋๋ค.
์๊ณ ํฐ์ง๋ Date ๊ฐ์ฒด๋ก๋ ๋น๊ต๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
4-8. ๋ง๋ฌด๋ฆฌ
DatePickCalendar์ ๋ง๋ค๊ธฐ ์ํ DatePickCalendar class๋ฅผ ์ดํด๋ณด์์ต๋๋ค. Calendar class์ ์์๋ฐ๊ณ ๋ ์ง๋ฅผ ์ ํํ ์ ์๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์์ต๋๋ค.
๋ค์์ ์ด๋ฒ ์์ ์ ํด๋นํ๋ commit์ ๋๋ค.
5. DatePick class
๋ง์ง๋ง์ผ๋ก ์ดํด๋ณผ ๊ฒ์ DatePick class์ ๋๋ค. ๋จ์ํ Date Picker Calendar๋ง ๋ณด์ฌ์ฃผ๋ ๊ฒ์ด ์๋๋ผ ์ ํ๋ ์์์ผ, ๋ง์ง๋ง์ผ์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ค์ผ ํ๊ณ ํด๋ฆญ์ผ๋ก Date Picker Calendar์ Open ํ๊ฑฐ๋ Close ํด์ผ ํ๊ธฐ ๋๋ฌธ์ eventListener์ ๋ํ ๋ก์ง๋ ์์ฑํด์ผ ํฉ๋๋ค.
DatePick class์ ์ ์ฒด ์ฝ๋๋ฅผ github ์ฃผ์๋ก ๋์ฒดํฉ๋๋ค. ์๋์ ์ฃผ์์์ ์ ์ฒด ์ฝ๋๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.
์ด์ด์ ๋ถ๋ถ์ ์ผ๋ก ํจ๊ป ์ดํด๋ณด๊ฒ ์ต๋๋ค.
5-1. constructor
class DatePicker {
#datePickerCalendar;
#isOpenCalendar = false;
constructor() {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
this.#datePickerCalendar = new DatePickerCalendar(year, month);
}
// ...
}
๋จผ์ constrcutor์ ๋๋ค. Schedule class์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ธ์คํด์ค๊ฐ ์์ฑ๋ ๋, ํ์ฌ ๋ , ์์ ๋ฐํ์ผ๋ก Calender ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค. ๋จ, ์ด๋ Calendar class๊ฐ ์๋๋ผ DatePickerCalendar class๋ฅผ ์ฌ์ฉํฉ๋๋ค. ์ดํ ์์ฑ๋ ์ธ์คํด์ค๋ฅผ #dataPickerCalendar์ ํ ๋นํฉ๋๋ค.
#isOpenCalendar๋ DatePickerCalendar๊ฐ ์ด๋ ธ๋์ง ๋ซํ๋์ง๋ฅผ boolean์ผ๋ก ๋ํ๋ด๋ private filed์ ๋๋ค.
5-2. initDatePicker, remove
initDatePicker = () => {
this.#datePickerCalendar.init();
this.#isOpenCalendar = false;
};
initDatePicker ๋ฉ์๋๋ ๋๊ฐ์ง์ ์ญํ ์ ํฉ๋๋ค.
1. #datePickerCalendar.init(): ์์์ผ๊ณผ ๋ง์ง๋ง์ผ์ null๋ก ์ด๊ธฐํํฉ๋๋ค.
2. #isOpenCalendar = close: Date Picker Calendar์ ๋ซ์ต๋๋ค.
initDatePicker ๋ฉ์๋๋ Date Picker ๋ฒํผ์ ํด๋ฆญํ ๋ ํธ์ถ๋์ด์ผ ํฉ๋๋ค.(๋ณ๋ค๋ฅธ ์ด์ ๊ฐ ์๋ค๋ฉด ์ฌ์ฉ์๋ ์ด๊ธฐ ํ๋ฉด ๊ตฌ์ฑ์ ๋ด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ป๊ฒ ํ ์ง ์ ํ๋ ๊ฑด ์ผ๋ฐ์ผ)
5-3. render, renderInput
render = () => {
const containerTemplate = `
<h1 class="title">Date Picker Calendar</h1>
<div class="date-picker-container">
<div class="date-picker-input-layout"></div>
</div>
`;
$('.calendar').innerHTML = container;
this.renderInput();
};
private renderInput = () => {
const startDate = this.#datePickerCalendar.getStartDate();
const endDate = this.#datePickerCalendar.getEndDate();
const inputTemplate = `
<div class="selected-date">
${
startDate
? `
<span>${format.date(startDate, '-')}</span>
<span>~</span>
<span>${endDate ? format.date(endDate, '-') : ''}</span>
`
: '<span class="not-selected-date">์์์ผ๊ณผ ์ข
๋ฃ์ผ์ ์ ํํด ์ฃผ์ธ์.</span>'
}
</div>
<button class="date-picker-input-button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 30 30" fill="none">
<path
d="M23.75 5H21.25V3.75C21.25 3.41848 21.1183 3.10054 20.8839 2.86612C20.6495 2.6317 20.3315 2.5 20 2.5C19.6685 2.5 19.3505 2.6317 19.1161 2.86612C18.8817 3.10054 18.75 3.41848 18.75 3.75V5H11.25V3.75C11.25 3.41848 11.1183 3.10054 10.8839 2.86612C10.6495 2.6317 10.3315 2.5 10 2.5C9.66848 2.5 9.35054 2.6317 9.11612 2.86612C8.8817 3.10054 8.75 3.41848 8.75 3.75V5H6.25C5.25544 5 4.30161 5.39509 3.59835 6.09835C2.89509 6.80161 2.5 7.75544 2.5 8.75V23.75C2.5 24.7446 2.89509 25.6984 3.59835 26.4017C4.30161 27.1049 5.25544 27.5 6.25 27.5H23.75C24.7446 27.5 25.6984 27.1049 26.4017 26.4017C27.1049 25.6984 27.5 24.7446 27.5 23.75V8.75C27.5 7.75544 27.1049 6.80161 26.4017 6.09835C25.6984 5.39509 24.7446 5 23.75 5ZM25 23.75C25 24.0815 24.8683 24.3995 24.6339 24.6339C24.3995 24.8683 24.0815 25 23.75 25H6.25C5.91848 25 5.60054 24.8683 5.36612 24.6339C5.1317 24.3995 5 24.0815 5 23.75V15H25V23.75ZM25 12.5H5V8.75C5 8.41848 5.1317 8.10054 5.36612 7.86612C5.60054 7.6317 5.91848 7.5 6.25 7.5H8.75V8.75C8.75 9.08152 8.8817 9.39946 9.11612 9.63388C9.35054 9.8683 9.66848 10 10 10C10.3315 10 10.6495 9.8683 10.8839 9.63388C11.1183 9.39946 11.25 9.08152 11.25 8.75V7.5H18.75V8.75C18.75 9.08152 18.8817 9.39946 19.1161 9.63388C19.3505 9.8683 19.6685 10 20 10C20.3315 10 20.6495 9.8683 20.8839 9.63388C21.1183 9.39946 21.25 9.08152 21.25 8.75V7.5H23.75C24.0815 7.5 24.3995 7.6317 24.6339 7.86612C24.8683 8.10054 25 8.41848 25 8.75V12.5Z"
fill="rgb(80, 80, 80)"
/>
</svg>
</button>
`;
$('.date-picker-input-layout').innerHTML = inputTemplate;
this.registerDatePickerButtonEventListener();
};
render ๋ฉ์๋๋ Date Picker Calendar์ title๊ณผ ์ ์ฒด์ ์ธ ๋ชจ์์ ์ก์ ์ค data-picker-container, date-picker-input-layout๋ฅผ ๋ง๋ค๊ณ ์ด๋ฅผ innerHTML๋ฅผ ํตํด calendar ๋ด๋ถ์ ์ถ๊ฐํฉ๋๋ค.
data-picker-input-layout์๋ ์์์ผ๊ณผ ๋ง์ง๋ง์ผ์ ๋ํ๋ด๋ input๊ณผ ๋ฌ๋ ฅ ์์ด์ฝ์ด ์์ต๋๋ค. ๋ฌ๋ ฅ ์์ด์ฝ์ ํด๋ฆญํ๊ฒ ๋๋ฉด ๋ ์ง๋ฅผ ์ ํํ ์ ์๋ Date Picker Calendar๊ฐ ๋ํ๋ฉ๋๋ค. ์ด๋ฌํ ์์ ์ render ๋ฉ์๋์์ renderInput ๋ฉ์๋๋ฅผ ํธ์ถํ๊ฒ ๋จ์ผ๋ก์จ ์ด๋ฃจ์ด์ง๋๋ค.
inputTemplate๋ฅผ ๋ง๋ค ๋, #datePickerCalendar์ startDate๊ฐ ์๋์ง์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ฝ๋๊ฐ ์์ฑ์ด ๋ฉ๋๋ค. ๋ง์ฝ startDate๊ฐ ์๋ค๋ฉด ์ฌ์ฉ์๊ฐ ์์ง ์์์ผ์ ์ ํํ์ง ์๋ ๊ฒฝ์ฐ์ด๊ธฐ ๋๋ฌธ์ '์์์ผ๊ณผ ์ข ๋ฃ์ผ์ ์ ํํด ์ฃผ์ธ์.'๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋ณด์ฌ์ง๋๋ค. ๋ง์ฝ startDate๊ฐ ์๋ค๋ฉด ์ฌ์ฉ์๊ฐ ์ ํํ๊ธฐ ์์ํ๋ ๊ฒฝ์ฐ์ด๊ธฐ ๋๋ฌธ์ '์์์ผ ~ ๋ง์ง๋ง์ผ'์ ํํ์ UI๊ฐ ๋ณด์ฌ์ง๋๋ค. ์ด๋ format.date() ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
svg๋ ๋ฌ๋ ฅ ์์ด์ฝ์ผ๋ก ํด๋ฆญํ๊ฒ ๋๋ฉด Date Pick Calendar๊ฐ ์คํ๋ ์ ์๋๋ก ํ์์ต๋๋ค. ํด๋ฆญ๊ณผ ๊ด๋ จ๋ ์ด๋ฒคํธ๋ 5-6์์ ๋ค๋ฃน๋๋ค.
5-4. renderCalendarContainer, renderCalendar ๋ฉ์๋
private renderCalendarLayout = () => {
const layoutTemplate = document.createElement('div');
layoutTemplate.className = 'date-picker-calendar-layout';
$('.date-picker-container').insertAdjacentElement(
'beforeend',
layoutTemplate
);
this.renderCalendar();
};
private renderCalendar = () => {
const isSelected = (date: Date) => {
return (
this.#datePickerCalendar.isEqualStartDate(date) ||
this.#datePickerCalendar.isEqualEndDate(date)
);
};
const yearMonthTemplate = `
<div class="date-picker-year-month">
${this.#datePickerCalendar.getYear()}๋
${this.#datePickerCalendar.getMonth()}์
</div>
`;
const calendarTemplate = `
<ul class="date-picker-calendar">
${['์ผ', '์', 'ํ', '์', '๋ชฉ', '๊ธ', 'ํ ']
.map(
(dayOfWeek) =>
`<div class="date-picker-day-of-week">${dayOfWeek}</div>`
).join('')}
${this.#datePickerCalendar
.getCalendarStorage()
.map(
({ day, state, date }) =>
`<li class="date-picker-calendar-day ${`${state}-month`} ${
this.#datePickerCalendar.isToday(date) ? 'today' : ''
} ${isSelected(date) ? 'selected' : ''} ${
this.#datePickerCalendar.isIncludedDate(date) ? 'included' : ''
}" data-date=${`${format.date(date, '-')}`}>${day}</li>`
).join('')}
</ul>
`;
$('.date-picker-calendar-layout').innerHTML = yearMonthTemplate + calendarTemplate;
this.registerCalendarDayEventListener();
};
renderCalendarLayout ๋ฉ์๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด๊ณณ์์๋ date-picker-calendar-layout์ ๋ง๋ค๊ณ insertAdjacentElement๋ฅผ ํ์ฉํ์ฌ date-picker-container์ ๊ฐ์ฅ ๋ง์ง๋ง ์์์ ์์น์ํต๋๋ค. data-picker-calendar-layout์ Date Picker Calendar์ ์ ์ฒด์ ์ธ ํ์ ์ก๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.(ex. position: absolute)
renderCalendarLayout ๋ฉ์๋๋ ์ฌ์ฉ์๊ฐ ๋ฌ๋ ฅ ์์ด์ฝ์ ํด๋ฆญํ ๋, ์คํ๋ฉ๋๋ค.
์ด ๋ถ๋ถ์ render ๋ฉ์๋์์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด ๋์ด๋ ๋ฉ๋๋ค. ์ ๋ Date Picker Calendar๊ฐ ์์ง ๋ณด์ด์ง ์๋๋ฐ Date Picker Calendar์ ๊ด๋ จ๋ layout์ด ์กด์ฌํ๋ ๊ฒ์ด ์ด์ํ์ฌ ๋๋์์ต๋๋ค.
๊ทธ ๋ค์์ renderCalendar ๋ฉ์๋์ ๋๋ค. ์ด๊ณณ์์ Date Picker Calendar์ UI๊ฐ ๋ง๋ค์ด์ง๋๋ค. isSelected ํจ์๋ Date๋ฅผ ๋ฐ์ ํด๋น Date๊ฐ ์ฌ์ฉ์์ ์ํด ์ ํ๋ Date์ธ์ง ํ๋ณํ๋ ์ญํ ์ ํฉ๋๋ค.
1. #datePickerCalendar.isEqualStartDate(date): date๊ฐ ์์์ผ๊ณผ ๊ฐ์์ง ํ๋จํฉ๋๋ค.
2. #datePickerCalendar.isEqualEndDate(date): date๊ฐ ๋ง์ง๋ง์ผ๊ณผ ๊ฐ์์ง ํ๋จํ๋ค.
yearMonthTemplate์ Date Picker Calendar์ ๋ , ์์ ๋ณด์ฌ์ฃผ๋ template์ ๋๋ค.
1. #datePickerCalendar.getYear(): Date Picker Calendar์ ๋ ์ ๊ฐ์ ธ์ต๋๋ค.
2. #datePickerCalendar.getMonth(): Date Picker Calendar์ ์์ ๊ฐ์ ธ์ต๋๋ค.
calendarTemplate์ Date Picker Calendar์ ํต์ฌ์ด๋ฉฐ ํน์ ๋ , ์์ day์ ๋ณด์ฌ์ค๋๋ค.
์ฌ๊ธฐ์ ๋ค์๊ณผ ๊ฐ์ด #datePickerCalendar์ ํ์ฉํ์ฌ ๋ฌ๋ ฅ์ ๋ง๋ค๊ณ ์คํ์ผ์ ํ์ํ class name์ ๋ง๋ญ๋๋ค.
1. #datePickerCalendar.getCalendarStorage(): ํ์ฌ ๋ฌ๋ ฅ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
2. #datePickerCalender.isToday(date): date๊ฐ ์ค๋์ธ์ง ํ๋จํฉ๋๋ค.
3. #datePickerCalendar.isIncludedDate(date): date๊ฐ ์ ํ๋ ๋ ์ง ์ฌ์ด์ธ์ง ํ๋จํฉ๋๋ค.
๋ํ date-set๋ฅผ ํ์ฉํ์ฌ ์ ํ๋ ๋ ์ง์ ๋ํ ์ ๋ณด๋ฅผ ๋ด์ต๋๋ค. ์ด๋ format.date() ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง yearMonthTemplate๊ณผ calendarTemplate์ innerHTML๋ฅผ ํตํด date-picker-calendar-layout์ ๊ทธ๋ ค์ง๋๋ค.
5-5. ์ด๋ฒคํธ ๋ฑ๋กํ๊ธฐ
private handleOpenCalender = () => {
if (this.#isOpenCalendar) {
this.#isOpenCalendar = false;
$('.date-picker-calendar-layout').remove();
return;
}
this.#isOpenCalendar = true;
this.renderCalendarLayout();
};
private handleSelectDate: EventListener = (event) => {
const day = event.target;
if (!(day instanceof HTMLLIElement)) return;
const date = day.dataset.date as string;
this.#datePickerCalendar.setDate(new Date(date));
this.renderInput();
this.renderCalendar();
};
private registerDatePickerButtonEventListener = () => {
$('.date-picker-input-button').addEventListener(
'click',
this.handleOpenCalender
);
};
private registerCalendarDayEventListener = () => {
$('.date-picker-calendar').addEventListener('click', this.handleSelectDate);
};
์ด๋ฒคํธ์ ๊ดํ ์ฝ๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
registerDatePickerButtonEventListener ๋ฉ์๋๋ rederInput ๋ฉ์๋๊ฐ ์คํ๋๋ฉด์ ํธ์ถ๋ฉ๋๋ค. rednerInput ๋ฉ์๋๋ฅผ ํตํด ๋ฌ๋ ฅ ์์ด์ฝ์ด ๊ทธ๋ ค์ง๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด ์์ด์ฝ์ ํตํด ์ฌ์ฉ์๋ Date Picker Calendar๋ฅผ ์ด๊ณ ๋ซ์ ์ ์์ต๋๋ค.
registerCalendarDayEentListener ๋ฉ์๋๋ renderCalendar ๋ฉ์๋๊ฐ ์คํ๋๋ฉด์ ํธ์ถ๋ฉ๋๋ค. renderCalendar ๋ฉ์๋์์ ๋ฌ๋ ฅ์ ์ผ(day)๊ฐ ๊ทธ๋ ค์ง๊ณ ์ฌ์ฉ์๋ ์ผ(day)์ ํด๋ฆญํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ฌ์ฉ์๊ฐ ๋ฌ๋ ฅ ์์ด์ฝ์ ํด๋ฆญํ๋ฉด handleOpenCalendar ๋ฉ์๋๊ฐ ์คํ๋ฉ๋๋ค. ์ฌ๊ธฐ์๋ #isOpenCalendar์ ๊ฐ์ ๋ฐ๋ผ ์ด๊ณ ๋ซ์์ง๋ฅผ ํ๋จํฉ๋๋ค. ๋ง์ฝ true๋ผ๋ฉด ๋ซ์์ผ ํ๊ธฐ ๋๋ฌธ์ date-picker-calendar-layout๋ฅผ ์ ๊ฑฐํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ false๋ผ๋ฉด ์ด์ด์ผ ํ๊ธฐ ๋๋ฌธ์ renderCalendarLayout ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
์ด๋ฒ์ ์ฌ์ฉ์๊ฐ ๋ฌ๋ ฅ์ ์ผ(day)์ ํด๋ฆญํ๋ค๊ณ ํฉ๋๋ค. ์ด๋, handleSelectDate ๋ฉ์๋๊ฐ ์คํ๋ฉ๋๋ค. ๋ฉ์๋ ๋ด๋ถ์์๋ #datePickerCalendar.setDate() ๊ฐ ์คํ๋๋๋ฐ ์ฌ๊ธฐ์ ์์์ผ ํน์ ๋ง์ง๋ง์ผ์ด ๋ฑ๋ก๋ฉ๋๋ค. ์์์ผ๊ณผ ๋ง์ง๋ง์ผ์ด ์ ๋ฐ์ดํธ๊ฐ ๋์์ผ๋ ํ๋ฉด๋ ๋ค์ ๊ทธ๋ ค์ผ ํฉ๋๋ค. ๋๋ฌธ์ renderInput() ๋ฉ์๋์ renderCalendar ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.
5-6. ๋ง๋ฌด๋ฆฌ
์์ฒญ ๊ธด ํํธ์์ต๋๋ค. ๊ทธ๋ ๊ฒ ๋ง์ ๊ธฐ๋ฅ์ด ์์ง ์๋๋ฐ ์ฝ๋๋์ด ์๋นํฉ๋๋ค. ์ด๋ template์ด ํฐ ๋น์ค์ ์ฐจ์งํ๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ๋๋ฌธ์ ๋ฆฌํฉํฐ๋ง์ ํ๊ฒ ๋๋ค๋ฉด template๋ฅผ ์ํ ํด๋๋ฅผ ๋ง๋ค๊ณ ๊ทธ๊ณณ์ ์ ๋ฆฌ๋ฅผ ํด๋ ๊ฒ ๊ฐ์ต๋๋ค.
์์ง ํ๋ฉด์์ Date Picker Calendar๋ฅผ ํ์ธํ ์ ์์ต๋๋ค. main.ts์ ์ด์ ๋ํ ์ฝ๋๊ฐ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ค์ ํํธ์์ ๋ฐ๋ก ์ด์ด ์งํํ๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ค์์ ์ด๋ฒ ์์
์ ๋ํ commit์
๋๋ค.(feat: ์ด ๋ ๋ฒ์ด๋ค์...?)
์ ์ปค๋ฐ ์ฝ๋์์ remove ๋ฉ์๋, unregisterEbentListener ๋ฉ์๋๋ ์ต์ ์ฝ๋์์๋ ์ ๊ฑฐ๋์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฏธ์ณ ๋ค๋ฃจ์ง ๋ชปํ ์์ค์ฝ๋์ ๋ํ github ์ฃผ์์ ๋๋ค.
๐ common.css๋ก Schedule Calendar์ Date Picker Calendar๊ฐ ๊ณตํต์ผ๋ก ์ฌ์ฉ๋๋ ์คํ์ผ์ด ์์ฑ๋ ํ์ผ์ ๋๋ค.
https://github.com/nlom0218/vanilla-calendar/blob/main/src/css/common.css
๐ datePicker.css๋ก Date Picker Calendar์์ ์ฌ์ฉ๋๋ ์คํ์ผ์ด ์์ฑ๋ ํ์ผ์ ๋๋ค.
https://github.com/nlom0218/vanilla-calendar/blob/main/src/css/datePicker.css
6. main.ts - Date Picker Calendar ๋ ๋๋ง
Date Picker Calendar๋ฅผ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ํด main.ts์ ์ฝ๋๋ฅผ ๋ค์๊ณผ ์ถ๊ฐ ์์ฑํฉ๋๋ค.
import DatePicker from './ts/DatePicker';
import Schedule from './ts/Schedule';
import { $ } from './ts/dom';
class App {
schedule;
datePicker;
constructor() {
this.schedule = new Schedule();
this.datePicker = new DatePicker();
}
init() {
this.schedule.render();
this.registerEventListener();
}
renderScheduleCalendar = () => this.schedule.render();
renderDatePickerCalendar = () => {
this.datePicker.initDatePicker();
this.datePicker.render();
};
registerEventListener = () => {
$('.schedule-button').addEventListener(
'click',
this.renderScheduleCalendar
);
$('.date-picker-button').addEventListener(
'click',
this.renderDatePickerCalendar
);
};
}
const app = new App();
app.init();
schedule button๊ณผ date picker button์ click ์ด๋ฒคํธ๋ฅผ ์ถ๊ฐํ์ต๋๋ค. ๋๋ฌธ์ ์ฌ์ฉ์๋ ๋ ๊ฐ์ ๋ฒํผ์ ์ฌ์ฉํ์ฌ ์ํ๋ ๋ฌ๋ ฅ์ ๋ณผ ์ ์์ต๋๋ค.
๊ฐ๊ฐ์ ๋ฒํผ์ ํด๋ฆญํ์ฌ Schedule ์ธ์คํด์ค ํน์ DatePicker ์ธ์คํด์ค์ render ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค. ๋ํ DatePicker๋ ์ด๊ธฐํ๋ฅผ ์ํด initDatePicker ๋ฉ์๋๋ ํจ๊ป ํธ์ถ๋ฉ๋๋ค.
์์ฑ๋ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋ค์์ main.ts์ ์ ๋ฐ์ดํธํ commit์ ๋๋ค.
์ด๋ฒ ์ฑํฐ์์ Calender ๊ฐ์ฒด๋ฅผ ํตํด ์ป์ ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ๋ ๊ฐ์ง ์ข ๋ฅ์ ๋ฌ๋ ฅ์ ๋ง๋ค์์ต๋๋ค. ํ์ง๋ง ์์ฌ์ด ์ ์ด ์์ต๋๋ค. ์ด์ ๋ฌ๊ณผ ๋ค์ ๋ฌ, ๊ทธ๋ฆฌ๊ณ navigation์ ํตํด ํน์ ๋ , ์๋ก ๋ฐ๋ก ์ด๋์ ํ ์ ์๋ค๋ ๊ฒ์ ๋๋ค. ์ด๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋ค์ ์ฑํฐ์์ ์ด์ด ํ๋๋ก ํ๊ฒ ์ต๋๋ค.