ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

๋ฐ˜์‘ํ˜•

๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ – ๋‚ ์งœ ์„ ํƒ๊ณผ ์›” ์ด๋™ ๊ธฐ๋Šฅ ๊ตฌํ˜„


์ง€๋‚œ ํŽธ์—์„œ ์šฐ๋ฆฌ๋Š” ๊ธฐ๋ณธ ๋‹ฌ๋ ฅ UI๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  ํ˜„์žฌ ์›”์˜ ๋‚ ์งœ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
์ด์ œ๋Š” ์‹ค์ œ๋กœ ๋™์ž‘ํ•˜๋Š” ์บ˜๋ฆฐ๋”, ์ฆ‰
โœ… ๋‚ ์งœ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ ,
โœ… ์ขŒ์šฐ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ด์ „/๋‹ค์Œ ๋‹ฌ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋Š”
๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


๐ŸŽฏ ๋ชฉํ‘œ

  • ๋‚ ์งœ ํด๋ฆญ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
  • ์ด์ „/๋‹ค์Œ ๋‹ฌ ์ด๋™ ๋ฒ„ํŠผ ์ถ”๊ฐ€ ๋ฐ ์ƒํƒœ ๊ด€๋ฆฌ
  • ํด๋ฆญ๋œ ๋‚ ์งœ์˜ ์‹œ๊ฐ์  ๊ฐ•์กฐ

๐Ÿง  ์‚ฌ์šฉ์ž ์ด๋ฒคํŠธ ์„ค๊ณ„ ํ๋ฆ„

โœ… ํ•„์š”ํ•œ ๋™์ž‘ ๋ชฉ๋ก

๋™์ž‘ ์„ค๋ช…

๋‚ ์งœ ํด๋ฆญ ํ•ด๋‹น ๋‚ ์งœ๋ฅผ ๊ฐ•์กฐํ•˜๊ณ , ์ดํ›„ ๊ธฐ๋Šฅ๊ณผ ์—ฐ๊ฒฐ
์ด์ „ ๋‹ฌ ํด๋ฆญ ํ˜„์žฌ ์›”์—์„œ -1 ์ด๋™
๋‹ค์Œ ๋‹ฌ ํด๋ฆญ ํ˜„์žฌ ์›”์—์„œ +1 ์ด๋™

๐Ÿ› ๏ธ 1. ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ ๋งŒ๋“ค๊ธฐ

โœ… CalendarState ์ธํ„ฐํŽ˜์ด์Šค ์ถ”๊ฐ€

// src/types.ts
export interface CalendarState {
  year: number;
  month: number;
  selectedDate?: Date;
}

๐Ÿ“ฆ 2. ์›” ์ „ํ™˜ ๋ฒ„ํŠผ ์ถ”๊ฐ€

โœ… HTML ํ…œํ”Œ๋ฆฟ ์ˆ˜์ •

// src/components/Calendar.ts (renderCalendar ๋‚ด๋ถ€)
  target.innerHTML = `
    <div class="calendar-header">
      <button class="prev-month">โ—€</button>
      <h2>${year}๋…„ ${month + 1}์›”</h2>
      <button class="next-month">โ–ถ</button>
    </div>
    <div class="calendar-grid">
      ${["์ผ", "์›”", "ํ™”", "์ˆ˜", "๋ชฉ", "๊ธˆ", "ํ† "]
        .map((d) => `<div class="calendar-cell header">${d}</div>`)
        .join("")}
      ${matrix
        .flat()
        .map((date) => {
          const day = date?.getDate();
          const inMonth = date?.getMonth() === month;
          const dateStr = date?.toISOString();
          return `<div class="calendar-cell${inMonth ? "" : " out"}" data-date="${dateStr}">${day}</div>`;
        })
        .join("")}
    </div>
  `;

๐Ÿงฉ 3. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์—ฐ๊ฒฐ

โœ… attachCalendarEvents ํ•จ์ˆ˜ ์ •์˜

๋ฐ˜์‘ํ˜•
// src/components/Calendar.ts
export function attachCalendarEvents(
  target: HTMLElement,
  state: CalendarState,
  rerender: () => void
) {
  // ๋‚ ์งœ ํด๋ฆญ
  const cells = target.querySelectorAll(".calendar-cell:not(.header)");
  cells.forEach((cell) => {
    cell.addEventListener("click", () => {
      const dateStr = cell.getAttribute("data-date");
      if (dateStr) {
        state.selectedDate = new Date(dateStr);
        rerender();
      }
    });
  });

  // ์›” ์ด๋™ ๋ฒ„ํŠผ
  const prevBtn = target.querySelector(".prev-month");
  const nextBtn = target.querySelector(".next-month");

  prevBtn?.addEventListener("click", () => {
    if (state.month === 0) {
      state.month = 11;
      state.year -= 1;
    } else {
      state.month -= 1;
    }
    rerender();
  });

  nextBtn?.addEventListener("click", () => {
    if (state.month === 11) {
      state.month = 0;
      state.year += 1;
    } else {
      state.month += 1;
    }
    rerender();
  });
}

๐Ÿ–ผ๏ธ 4. ์„ ํƒ๋œ ๋‚ ์งœ ์Šคํƒ€์ผ ๊ฐ•์กฐ

โœ… ์„ ํƒ๋œ ๋‚ ์งœ ๋น„๊ต ์ถ”๊ฐ€

// ๋‚ ์งœ ์…€ ๋ Œ๋”๋ง ๋ถ€๋ถ„ (์ถ”๊ฐ€)
const isSelected = date?.toDateString() === state.selectedDate?.toDateString();
return `<div class="calendar-cell${inMonth ? "" : " out"}${isSelected ? " selected" : ""}" data-date="${dateStr}">${day}</div>`;

๐ŸŽจ 5. CSS ์Šคํƒ€์ผ ์ถ”๊ฐ€

.calendar-cell.selected {
  background-color: #007bff;
  color: #fff;
  font-weight: bold;
}

.calendar-header button {
  background: none;
  border: none;
  font-size: 1.2rem;
  cursor: pointer;
  padding: 0 1rem;
}

๐Ÿš€ 6. index.ts ์—…๋ฐ์ดํŠธ

import { renderCalendar, attachCalendarEvents } from "./components/Calendar";
import { CalendarState } from "./types";

const root = document.getElementById("calendar-root");
const state: CalendarState = {
  year: new Date().getFullYear(),
  month: new Date().getMonth(),
};

function render() {
  if (root) {
    renderCalendar(root, state.year, state.month, state);
    attachCalendarEvents(root, state, render);
  }
}

render();

โœ… ๊ฒฐ๊ณผ ํ™•์ธ

npm run dev
  • ๋‚ ์งœ ํด๋ฆญ ์‹œ ์Šคํƒ€์ผ์ด ๊ฐ•์กฐ๋จ
  • โ—€, โ–ถ ๋ฒ„ํŠผ์œผ๋กœ ์›” ์ด๋™ ๊ฐ€๋Šฅ
  • ์„ ํƒ๋œ ๋‚ ์งœ๋Š” ์œ ์ง€๋˜๋ฉฐ ๊ฐ•์กฐ ํ‘œ์‹œ๋จ

๐Ÿ“š ์ฐธ๊ณ ์ž๋ฃŒ

 


๋‹ค์Œ ํŽธ ์˜ˆ๊ณ :
๐Ÿ“˜ 6ํŽธ – ์ผ์ • ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌํ•˜๊ธฐ: ์ด๋ฒคํŠธ ์ถ”๊ฐ€ ๋ฐ ๋ฐ์ดํ„ฐ ์ €์žฅ ๊ตฌ์กฐ ์„ค๊ณ„
์‚ฌ์šฉ์ž๊ฐ€ ์„ ํƒํ•œ ๋‚ ์งœ์— ์ผ์ •์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ด…๋‹ˆ๋‹ค! ๐Ÿ—“๏ธ
๋“œ๋””์–ด “์ง„์งœ ์ผ์ • ํ”Œ๋Ÿฌ๊ทธ์ธ”์œผ๋กœ ์ง„ํ™”ํ•˜๋Š” ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค!

'study > ts' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์ผ์ • ์‚ญ์ œ ๋ฐ ์ˆ˜์ • ๊ธฐ๋Šฅ ์ถ”๊ฐ€ํ•˜๊ธฐ โ€“ ์ธํ„ฐ๋ž™์…˜ ๊ฐ•ํ™”  (0) 2025.03.27
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์ผ์ • ๋ฐ์ดํ„ฐ ์˜๊ตฌ ์ €์žฅ โ€“ LocalStorage ์—ฐ๋™์œผ๋กœ ์ƒˆ๋กœ๊ณ ์นจ์—๋„ ์œ ์ง€ํ•˜๊ธฐ  (0) 2025.03.26
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์ผ์ • ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌํ•˜๊ธฐ โ€“ ์ด๋ฒคํŠธ ์ถ”๊ฐ€ ๋ฐ ์ €์žฅ ๊ตฌ์กฐ ์„ค๊ณ„  (0) 2025.03.25
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌ์กฐ ์„ค๊ณ„ โ€“ ๋‚ ์งœ ๋ Œ๋”๋ง์„ ์œ„ํ•œ UI ๊ธฐ๋ณธ ๊ตฌ์„ฑ  (0) 2025.03.24
๐Ÿ“Œ Webpack๊ณผ TypeScript๋กœ ๋งŒ๋“œ๋Š” ์›น์•ฑ ์บ˜๋ฆฐ๋” ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ ์‹œ๋ฆฌ์ฆˆ - Webpack ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ธฐ โ€“ ๋ฒˆ๋“ค๋ง ๊ฐœ๋…๊ณผ ์„ค์ • ํŒŒ์ผ ์™„์ „ ๋ถ„์„  (0) 2025.03.24
โ€ป ์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค.
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2025/04   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
๊ธ€ ๋ณด๊ด€ํ•จ
๋ฐ˜์‘ํ˜•