카테고리 없음

js로 현재 기준 달력 만들기

최종군 2024. 11. 3. 17:53
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>다음 달로 넘어가는 30일 범위 클릭 가능한 달력</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f4f4f4;
            text-align: center;
            padding: 20px;
            height: 100vh;
            display: flex;
            justify-content: center;
            flex-direction: column;
        }
        table {
            margin: 0 auto;
            border-collapse: collapse;
            width: 80vh;
            height: 70vh;
            box-shadow: 0 3px 5px rgba(0.5, 0.5, 0.5, 0.5);
        }
        th, td {
            border: 1px solid #ddd;
            padding: 10px;
            text-align: center;
        }
        th {
            background-color: tomato;
            color: white;
            position: relative;
        }
        button {
            background-color: #fff;
            border: none;
            width: 100%;
            height: 100%;
            cursor: pointer;
            background-color: transparent;
        }
        button.disabled {
            background-color: #f0f0f0;
            color: #999;
            cursor: not-allowed;
        }
        button.disabled:hover {
            background-color: #f0f0f0;
            transform: none;
            color: #999;
        }
        button.enabled:hover {
            background-color: #e7e7e7;
            transform: scale(1.3);
            color: red;
        }
        .today {
            background-color: lightblue;
        }
        .nav-button {
            width: 70px;
            height: 50px;
            margin: 10px;
            padding: 10px;
            background-color: tomato;
            color: white;
            border: none;
            cursor: pointer;
           
        }
        .nav-button:hover {
            background-color: #ff7f7f;
        }
        #prev-btn{
            width: 30px;
            height: 30px;
            position: absolute;
            top: 20.7%;
            left: 43%;
            border: 1px solid white;
            border-radius: 50px;
            display: flex;
            justify-content: center;
            flex-direction: column;
            align-items: center;
         
        }
        #next-btn{
            position: absolute;
            width: 30px;
            height: 30px;
            top: 20.7%;
            right:43%;
            border: 1px solid white;
            border-radius: 50px;
       
            display: flex;
            justify-content: center;
            flex-direction: column;
            align-items: center;
        }
        span{
            display: block;
            margin-bottom: 5px;
            font-size: 1.4em;
        }
        #next-btn span{
            margin-top: -10px;
            margin-left: -3px;
        }
        #prev-btn span{
            margin-top: -10px;
            margin-left: -6px;

        }
        .today{
            color: red !important;
        }
     


    </style>
</head>
<body>
    <div id="calendar">
    </div>
    <button class="nav-button" id="prev-btn" onclick="changeMonth(-1)">
        <span></span>
    </button>
   
    <button class="nav-button" id="next-btn" onclick="changeMonth(1)">
        <span></span>
    </button>

    <script>
        let currentMonthOffset = 0;  // 현재 달을 기준으로 얼마나 이동했는 지 추적
        let MaxMonth = 2;
        function createCalendar() {
            const today = new Date(); // Date 객체 생성 : 현재 날짜와 시간을 가져온다.

            /* 1. 현재 월을 기준으로 */
            today.setMonth(today.getMonth() + currentMonthOffset);
            const currentMonth = today.getMonth();
            const year = today.getFullYear(); // 년도 4자리를 호출하는 메소드이다
            const currentDay = new Date().getDate();
            /*현재 월을 기준으로 */
           
            /*today가 있는데 currentDay를 new Date().getDate(); 구하는 이유?? */

            // const today = new Date();로 생성된 Date 객체는 현재 날짜와 시간은을 포함한다.
            // new Date().getDate();로 얻은 값으로, 현재 월의 몇 번째 날인지를 나타낸다.

            /*현재 달의 첫 번째 */
            const firstDay = new Date(year, currentMonth, 1);
            // 특정 연도의 첫번째 날을 나타낸다. 맨 뒤 1은
            // 지정된 연도와 지정된 날의 1일을 의미한다.
            /*현재 달의 첫 번째 */

            /*다음달의 마지막 날을 구하는 코드*/
            const lastDay = new Date(year, currentMonth + 1, 0);
            // currentMonth + 1 현재 월에 1을 더한 값으로 다음달을 나타낸다.
            // 날짜를 0으로 설정하면, 해당 월의 마지막 날을 반환한다.
            /*다음달의 마지막 날을 구하는 코드*/

            /*
                현재 달의 첫 번째 날과 다음 달의 마지막 날을 알고 있으면
                빈칸을 추가하고 날짜를 정확한 위치에 표시할 수 있어서 달력이 보기 좋게 된다
           
            */
            const daysInMonth = lastDay.getDate();
            // 다음 달의 마지막 날짜를 생성한다.
            // 10월이 31일이라면 31일을 반환한다.


            // 오늘 기준으로 30일 뒤 계산
            const startDate = new Date(); // 오늘 날짜 기준
            const futureDate = new Date();
            futureDate.setDate(startDate.getDate() + 30); // 30일 뒤
           
            let calendarHtml = '';
           
            calendarHtml += '<table>'
            + '<tr><th colspan="7">' + year + '년 ' + (currentMonth + 1) + '월</th></tr>'
            + '<tr><th>일</th><th>월</th><th>화</th><th>수</th><th>목</th><th>금</th><th>토</th></tr>'
            + '<tr>';

            const firstDayOfWeek = firstDay.getDay();
            for (let i = 0; i < firstDayOfWeek; i++) {
                calendarHtml += '<td></td>';
            }
            // getDay() 메소드는 해당 날짜가 주의 몇 번쨰 요일인지를 반환해준다.
            // 0 일요일 6 토요일

            // 날짜 추가
            for (let day = 1; day <= daysInMonth; day++) {
                if ((day + firstDayOfWeek - 1) % 7 === 0 && day !== 1) {
                    calendarHtml += '</tr><tr>'; // 줄바꿈
                }
            // day + firstDayOfWeek - 1 현재 날짜day와 첫 번째 날의 요일
            // firstDayOfWeek을 더 한 후 1을 빼서 전체 날짜를 계산한다.
            // 한 주의 마지막 날짜인 경우(일요일)인 경우 줄바꿈을 해준다.


                const thisDate = new Date(year, currentMonth, day);

                let isClickable = thisDate >= startDate && thisDate <= futureDate;
                // 날짜 클릭 가능 여부 thisDate가 오늘 날짜와 30일 후 사이에 있는 지 여부를 확인한다.


                let classList = "";
               
                // 오늘 날짜 강조
                if (thisDate.toDateString() === new Date().toDateString()) {
                    classList += "today";
                   
                   
                }
                // toDateString() => thisDate 객체를 문자열 형태로 변환하여 날짜와
                // 시간을 제외한 "YYYY-MM-DD" 형식으로 반환한다.


                // 버튼 생성
                if (isClickable) {
                    calendarHtml += `
                        <td>
                            <button class="enabled ${classList}" onclick="dateClicked(${day})">${day}</button>
                        </td>
                    `;
                    // enabled 주로 사용자 인터페이스에서 버튼이나 입력 필드가 활성화되어 사용자가
                    // 상호작용할 수 있는 상태를 의미한다.

                } else {
                    calendarHtml += `
                        <td>
                            <button class="disabled ${classList}" disabled>${day}</button>
                        </td>
                    `;
                }
            }
             calendarHtml += '</tr></table>';

            document.getElementById('calendar').innerHTML = calendarHtml;
            // 다음 버튼 처리
            if (currentMonthOffset + 1< MaxMonth) {
                document.getElementById('next-btn').style.display = 'block';  
            } else {
                document.getElementById('next-btn').style.display = 'none';  
            }

            // 이전 버튼 처리
            if (currentMonthOffset  - 2 > -MaxMonth) {
                document.getElementById('prev-btn').style.display = 'block';    // 이전 버튼 보이기
            } else {
                document.getElementById('prev-btn').style.display = 'none';    // 이전 버튼 숨기기
            }

        }
        function dateClicked(day) {
            const today = new Date();
            const month = today.getMonth() + 1 + currentMonthOffset; // 현재 월 + 오프셋
            const year = today.getFullYear();
            confirm(`선택한 날짜: ${year}${month}${day}일로 예약 진행하겠습니까?`);
        }

        function changeMonth(offset) {
            if (currentMonthOffset + offset < MaxMonth && currentMonthOffset + offset > -MaxMonth) {
        currentMonthOffset += offset;
    }
            createCalendar();
        }
        createCalendar();
     

    </script>
</body>
</html>