본문 바로가기

백엔드

[Django] 장고 캘린더 예약 사이트 만들기 (1 - 달력구현)

개발 동기

동아리에서 스터디나 행사 관련해서 약속을 잡을때 매주 카톡으로 투표 및 조율을 하는 상황이 너무 피곤해서 사이트로 예약 어플을 만들면 편할것 같아서 개발하게 되었다.

 

개발 순서
1. 달력 구현 (HTML, CSS, JS)
2. 날짜 선택 구현 (CSS, JS)
3. 예약 구현 (JS, DATABASE, DJANGO)

[1. 달력 구현]

참고 블로그: https://bigtop.tistory.com/68?category=827794

 

[JavaScript] 일반적인 달력 만들기 - 영상

자바스크립트로 간단한 달력 만들기에 이어서 일반적인 달력 만들기를 영상으로 녹화해봤습니다. 의도치 않게 오랜시간이 지나서야 이 영상을 제작하게 되었는데, 막상 시간이 지나서 제가 작

bigtop.tistory.com

BigTop_Log 님의 글과 코드를 바탕으로 달력을 제작하였습니다.

 

결과물

 


코드

-HTML

{% extends 'index.html' %}
{% load static %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/calender/calender.css' %}">
<div class="calendar">
        <div class="calendar_header">
            <div class="ym-wrapper">
                <span class="year"></span><span class="month"></span></div>
            <div class="calendar_nav">
                <button class="nav-btn go-prev">&lt;</button>
                <button class="nav-btn go-today">오늘</button>
                <button class="nav-btn go-next">&gt;</button>
            </div>
        </div>
        <div class="calendar_main">
            <div class="days">
                <div class="day"></div>
                <div class="day"></div>
                <div class="day"></div>
                <div class="day"></div>
                <div class="day"></div>
                <div class="day"></div>
                <div class="day"></div>
            </div>
            <div class="dates"></div>
        </div>
    </div>
    <script src="{% static 'js/calender/calender.js' %}"></script>
    <script src="{% static 'js/calender/reserve.js' %}"></script>
{% endblock %}


-CSS

.calendar {
    width: 70%;
    margin: auto;
    padding-bottom: 50px;
}

.calendar_header {
    display: inline-block;
}

.ym-wrapper {
    font-size: 35px;
}

.calendar_nav {
    display: flex;
    flex-grow: 0;
    flex-shrink: 0;
    justify-content: center;
    align-items: center;
    border: 1px solid #333333;
}

.nav-btn {
    width: 28px;
    height: 30px;
    border: none;
    font-size: 16px;
    line-height: 34px;
    background-color: transparent;
    cursor: pointer;
}

.go-today {
    width: 80%;
    border-left: 1px solid #333333;
    border-right: 1px solid #333333;
}

.calendar_main{
    border-collapse: collapse;
    width: 100%;
}

.days {
    display: flex;
    margin: 25px 0 10px;
}

.day {
    width: calc(100% / 7);
    text-align: center;
    transition: all .3s;
}

.dates {
    display: flex;
    flex-flow: row wrap;
    border: 1px solid #333333;
}

.date {
    cursor: pointer;
    width: calc(100% / 7);
    padding: 5% 2%;
    text-align: center;
    border: 1px solid #333333;
    transition: all .3s;
}

.day:nth-child(7n + 1),
.date:nth-child(7n + 1) {
    color: #D13E3E;
}

.day:nth-child(7n),
.date:nth-child(7n) {
    color: #396EE2;
}

.other {
    color: rgba(88, 88, 88, 0.315) !important;
}

.today {
    position: relative;
    background-color: #ff1c1c96;
}

.selected{
    background-color: black;
    color: #ffffff !important;
}


-JS

let date = new Date();

const renderCalender = () => {
    const viewYear = date.getFullYear();
    const viewMonth = date.getMonth();

    document.querySelector('.year').textContent = `${viewYear}`;
    document.querySelector('.month').textContent = `${viewMonth + 1}`;

    const prevLast = new Date(viewYear, viewMonth, 0);
    const thisLast = new Date(viewYear, viewMonth + 1, 0);

    const PLDate = prevLast.getDate();
    const PLDay = prevLast.getDay();

    const TLDate = thisLast.getDate();
    const TLDay = thisLast.getDay();

    const prevDates = [];
    const thisDates = [...Array(TLDate + 1).keys()].slice(1);
    const nextDates = [];

    if (PLDay !== 6) {
        for (let i = 0; i < PLDay + 1; i++) {
            prevDates.unshift(PLDate - i);
        }
    }

    for (let i = 1; i < 7 - TLDay; i++) {
        nextDates.push(i);
    }

    const dates = prevDates.concat(thisDates, nextDates);
    const firstDateIndex = dates.indexOf(1);
    const lastDateIndex = dates.lastIndexOf(TLDate);

    dates.forEach((date, i) => {
        const condition = i >= firstDateIndex && i < lastDateIndex + 1 ?
            'this' :
            'other';
        dates[i] = `<div class="date ${condition}">${date}</div>`;
    });

    document.querySelector('.dates').innerHTML = dates.join('');

    const today = new Date();
    if (viewMonth === today.getMonth() && viewYear === today.getFullYear()) {
        for (let date of document.querySelectorAll('.this')) {
            if (+date.innerText === today.getDate()) {
                date.classList.add('today');
                break;
            }
        }
    }
};

renderCalender();

const prevMonth = () => {
    date.setMonth(date.getMonth() - 1);
    renderCalender();
};

const nextMonth = () => {
    date.setMonth(date.getMonth() + 1);
    renderCalender();
};

const goToday = () => {
    date = new Date();
    renderCalender();
};


참고 하였던 BigTop_Log님의 코드중 연도와 월을 표시하는 부분과 일별 태그의 구조및 CSS를 일부 수정하였다.