예제 오늘날짜 셋팅(class="today") 달력 특정날짜 셋팅(value="1984-05-19") 달력 오늘 이전 선택 불가(class="disabledPrev") 달력 오늘 이후 선택 불가(class="disabledNext") 달력 이전, 다음 개월수 제한(min-month="3" max-month="14") 달력
코드 - html 달력 달력 달력 달력 달력 - css .form-date { display:inline-block; position:relative; } .form-date_btn { position:absolute; top:50%; right:0; transform:translateY(-50%); width:40px; height:40px; color:transparent; font-size:1px; line-height:1px; } .form-date_btn:before, .form-date_btn:after { content:''; position:absolute; left:50%; transform:translateX(-50%); width:20px; box-sizing:border-box; } .form-date_btn:before { top:10px; height:20px; border:2px solid #999; } .form-date_btn:after { top:15px; height:2px; background-color:#999; } /* 달력 레이어 */ .calendar { display:none; position:fixed; z-index:50; width:300px; margin-top:10px; border-radius:8px; box-shadow:0 4px 12px rgba(0, 0, 0, 0.08); background:#fff; opacity:0; transition:opacity .2s; } .calendar.btm {margin:0 0 10px;} .calendar button { padding:0; border:0; background-color:transparent; color:inherit; text-align:left; cursor:pointer; } .calendar button:disabled {cursor:default;} .calendar_info { position:relative; border-bottom:1px solid #e7ecf3; text-align:center; } .calendar_info .date-text { display:inline-block; height:48px; color:#242b2e; font-size:16px; line-height:48px; } .calendar_info .info_btn { position:absolute; top:50%; transform:translateY(-50%); width:20px; height:20px; font-size:0; text-indent:-99999px; line-height:0; } .calendar_info .btn_year_prev {left:20px;} .calendar_info .btn_month_prev {left:40px;} .calendar_info .btn_year_next {right:20px;} .calendar_info .btn_month_next {right:40px;} .calendar_info .info_btn:disabled {opacity:0.4;} .calendar_info .info_btn:before { content:''; position:absolute; top:50%; left:50%; width:6px; height:6px; border-width:2px 2px 0 0; border-style:solid; border-color:#565c63; } .calendar_info .btn_year_prev:before { transform:translate(-50%,-50%) rotate(-135deg); margin-left:5px; } .calendar_info .btn_month_prev:before { transform:translate(-50%,-50%) rotate(-135deg); margin-left:2px; } .calendar_info .btn_year_next:before { transform:translate(-50%,-50%) rotate(45deg); margin-left:-5px; } .calendar_info .btn_month_next:before { transform:translate(-50%,-50%) rotate(45deg); margin-left:-2px; } .calendar_info .btn_year_prev:after, .calendar_info .btn_year_next:after { content:''; position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:2px; height:12px; background-color:#565c63; border-radius:2px; } .calendar_info .btn_year_prev:after {margin-left:-3px;} .calendar_info .btn_year_next:after {margin-left:3px;} .calendar_table { margin-top:4px; padding:0 26px 26px; } .calendar_table .tbl { table-layout:fixed; border-collapse:collapse; border-spacing:0; width:100%; } .calendar_table .tbl th, .calendar_table .tbl td { color:#778088; font-size:16px; font-weight:normal; text-align:center; } .calendar_table .tbl th {height:44px;} .calendar_table .tbl td .btn-date { position:relative; width:100%; height:40px; color:#242b2e; text-align:center; } .calendar_table .tbl td .btn-date:disabled {color:#ccc;} .calendar_table .tbl td .btn-date .date { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:32px; height:32px; border-radius:50%; text-align:center; line-height:32px; } /* today */ .calendar_table .tbl td.today .btn-date .date {background-color:#eceef4;} /* active */ .calendar_table .tbl td.active .btn-date .date { background-color:#3f44de; color:#fff; } - script $(document).ready(function(){ jsCalendarSet(); }); $(window).resize(function(){ jsCalendarLayer(); }); $(window).scroll(function(){ jsCalendarLayer(); }); /* 달력 */ function jsCalendarSet(){ $('.jsDateForm').each(function(){ $('body').append(''); }); $('.jsCalendar').prevAll('.jsCalendar').remove(); jsCalendar(); } calendarIdx = 0; calendarIdxYear = 0; calendarIdxMonth = 0; function jsCalendar(y, m, callback){ //픽스 var todayDate = new Date(); var tYear = todayDate.getFullYear(); var tMonth = todayDate.getMonth(); var tDate = todayDate.getDate(); var today = tYear + ('0' + (tMonth + 1)).slice(-2) + ('0' + tDate).slice(-2);//오늘 날짜 //변동 if(y){ var newDate = new Date(y, m); }else{ var newDate = new Date(); } var year = newDate.getFullYear(); var month = m; var month = newDate.getMonth(); var monthTxt = month + 1; var date = newDate.getDate(); var dayIdx = newDate.getDay(); var dayArr = ["일", "월", "화", "수", "목", "금", "토"]; var day = dayArr[dayIdx]; var lastDatePrev = new Date(year, month, 0).getDate();//지난달 마지막 날짜 var firstDateNow = new Date(year, month).getDay();//이번달 처음 날짜 인덱스 var lastDateNow = new Date(year, month + 1, 0).getDate();//이번달 마지막 날짜 //년월 출력 var YearMonth = year + ('0' + monthTxt).slice(-2); //tr 생성 개수 if(firstDateNow + lastDateNow <= 35){ if(firstDateNow + lastDateNow <= 28){ var trLen = 4; }else{ var trLen = 5; } }else{ var trLen = 6; } /* 인풋 */ $('.jsDateFiled').each(function(){ var vlu = $(this).val(); if($(this).closest('.today').hasClass('today')){ var todayVal = tYear + '-' + ('0' + (tMonth + 1)).slice(-2) + '-' + ('0' + tDate).slice(-2); }else{ var todayVal = $(this).val(); } $(this).val(todayVal).attr('full', vlu.replace(/[^0-9]/g, '')); //오늘 이전 선택 불가 if($(this).closest('.jsDateForm').hasClass('disabledPrev')){ $(this).closest('.jsDateForm').attr('min-month', '0'); } //오늘 이후 선택 불가 if($(this).closest('.jsDateForm').hasClass('disabledNext')){ $(this).closest('.jsDateForm').attr('max-month', '0'); } }); $('.jsCalendar').each(function(){ $(this).removeAttr('year month').html(''); /* 연, 월 데이터 */ $(this).attr({ 'year':year, 'month':month }); $(this).append(''); /* 상단 인포메이션 생성 */ var info = ''; info += ''; info += '' + year + '년 ' + monthTxt + '월'; info += '이전 연도'; info += '이전 월'; info += '다음 월'; info += '다음 연도'; info += ''; $(this).find('.calendar_inner').append(info); /* 달력 생성 */ var calTbl = ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += ''; calTbl += '일'; calTbl += '월'; calTbl += '화'; calTbl += '수'; calTbl += '목'; calTbl += '금'; calTbl += '토'; calTbl += ''; calTbl += ''; calTbl += ''; for(i = 0; i < trLen; i ++){ calTbl += ''; calTbl += ''; calTbl += ''; } calTbl += ''; calTbl += ''; calTbl += ''; $(this).find('.calendar_inner').append(calTbl); //첫째 주 날짜 설정 $(this).find('.calendar_table .tbl tr:nth-child(1) td').each(function(){ var prev = (lastDatePrev + 1) - firstDateNow; var idx = $(this).index(); $(this).html('' + (prev + idx) + ''); }); $(this).find('.calendar_table .tbl tr:nth-child(1) td').eq(firstDateNow).attr({ 'year':year, 'month':monthTxt, 'date':'1', 'full':YearMonth + '01' }); $(this).find('.calendar_table .tbl tr:nth-child(1) td').eq(firstDateNow).html('1'); $(this).find('.calendar_table .tbl tr:nth-child(1) td').eq(firstDateNow).nextAll('td').each(function(){ var idx = $(this).index(); var date = (idx + 1) - firstDateNow; $(this).attr({ 'year':year, 'month':monthTxt, 'date':date, 'full':YearMonth + ('0' + date).slice(-2) }); $(this).html('' + date + ''); }); //나머지 날짜 설절 for(i = 1; i < 6; i ++){ var last = Number($(this).find('.calendar_table .tbl tr:nth-child(' + i + ') td:last-child').attr('date')); $(this).find('.calendar_table .tbl tr:nth-child(' + (i + 1) + ') td').each(function(){ var idx = $(this).index() + 1; var date = last + idx; $(this).attr({ 'year':year, 'month':monthTxt, 'date':date, 'full':YearMonth + ('0' + date).slice(-2) }); $(this).html('' + date + ''); }); } var prevLen = $(this).find('.calendar_table td[date=' + lastDateNow + ']').prevAll('td').length; $(this).find('.calendar_table td[date=' + lastDateNow + ']').nextAll('td').each(function(){ var idx = $(this).index() - (prevLen + 1); $(this).removeAttr('year month date full'); $(this).html('' + (idx + 1) + ''); }); //토요일 $(this).find('.calendar_table td:last-child').addClass('saturday'); //일요일 $(this).find('.calendar_table td:first-child').addClass('sunday'); //오늘 표시 $(this).find('.calendar_table td[full=' + today + ']').addClass('today'); /* 콜백 */ if(callback){ callback(true); } /* focus */ $(this).find('.calendar_info .info_btn').off('focus'); $(this).find('.calendar_info .info_btn').on('focus', function(){ var cls = $(this).attr('class').replace(/info_btn /g, ''); $(this).closest('.jsCalendar').attr('focus', cls); }); /* 이전, 다음 버튼 클릭 */ $(this).find('.calendar_info .info_btn').off('click'); $(this).find('.calendar_info .info_btn').on('click', function(){ var year = Number($(this).closest('.jsCalendar').attr('year')); var month = Number($(this).closest('.jsCalendar').attr('month')); if($(this).hasClass('btn_year_prev')){ //이전 연도 if($('.jsDateForm[min-month]').hasClass('active') || $('.jsDateForm[max-month]').hasClass('active')){ calendarIdx --; calendarIdxYear = calendarIdx * 12; } jsCalendar(year - 1, month, function(){ selDate(); }); }else if($(this).hasClass('btn_year_next')){ //다음 연도 if($('.jsDateForm[min-month]').hasClass('active') || $('.jsDateForm[max-month]').hasClass('active')){ calendarIdx ++; calendarIdxYear = calendarIdx * 12; } jsCalendar(year + 1, month, function(){ selDate(); }); }else if($(this).hasClass('btn_month_prev')){ //이전 월 if($('.jsDateForm[min-month]').hasClass('active') || $('.jsDateForm[max-month]').hasClass('active')){ calendarIdxMonth --; } jsCalendar(year, month - 1, function(){ selDate(); }); }else if($(this).hasClass('btn_month_next')){ //다음 월 if($('.jsDateForm[min-month]').hasClass('active') || $('.jsDateForm[max-month]').hasClass('active')){ calendarIdxMonth ++; } jsCalendar(year, month + 1, function(){ selDate(); }); } }); /* 날짜 선택 */ $(this).find('.btn-date').off('click'); $(this).find('.btn-date').on('click', function(){ var selDate = $(this).closest('td').attr('full'); var date = selDate.substring(0, 4) + '-' + selDate.substring(4, 6) + '-' + selDate.substring(6, 8); $(this).closest('.jsCalendar').attr({ 'select':selDate, 'idx':calendarIdx, 'idx-year':calendarIdxYear, 'idx-month':calendarIdxMonth }); $(this).closest('.jsCalendar').find('td').removeClass('active').find('.btn-date').removeAttr('title'); $(this).closest('td').addClass('active').find('.btn-date').attr('title', '선택됨'); $('.jsDateForm.active .jsDateBtn').focus(); $('.jsDateForm.active').removeClass('active').find('.jsDateFiled').val(date).attr('full', selDate); $(this).closest('.jsCalendar').fadeOut(100); }); //접근성 탭 생성 $(this).prepend('이전'); $(this).append('다음'); $(this).find('.tabIdx').css({ 'position':'fixed', 'top':'-99999px', 'left':'-99999px', 'width':'0', 'height':'0', 'opacity':'0' }); //접근성 탭 포커스 $(this).find('.tabIdx').off('focus'); $(this).find('.tabIdx').on('focus', function(){ if($(this).hasClass('prev')){ $(this).closest('.jsCalendar').find('td[date=' + lastDateNow + '] .btn-date').focus(); }else{ $(this).closest('.jsCalendar').find('.calendar_inner').focus(); } }); }); /* 달력 열기 버튼 */ $(document).off('click', '.jsDateBtn'); $(document).on('click', '.jsDateBtn', function(){ var $form = $(this).closest('.jsDateForm'); var valLen = $form.find('.jsDateFiled').val().length; if(valLen > 0){ var date = $form.find('.jsDateFiled').val(); }else{ var date = today; $('.jsCalendar').attr({ 'idx':'0', 'idx-year':'0', 'idx-month':'0' }); } var full = date.replace(/[^0-9]/g, ''); var yyyy = full.substring(0, 4); var mm = Number(full.substring(4, 6)) - 1; if($('.jsDateForm').hasClass('active')){ $('.jsDateForm.active').removeClass('active').find('.jsDateBtn').focus(); $('.jsCalendar').fadeOut(100, function(){ $(this).css('opacity', '0'); }); }else{ $('.jsDateForm.active').removeClass('active').find('.jsDateBtn').focus(); $('.jsCalendar').fadeOut(100, function(){ $(this).css('opacity', '0'); }); $('.jsDateForm').removeClass('active'); $form.addClass('active'); jsCalendar(yyyy, mm, function(){ $('.jsCalendar').removeAttr('select'); $('.jsCalendar .calendar_table td').removeClass('active').find('.btn-date').removeAttr('title'); if(valLen > 0){ $('.jsCalendar .calendar_table td[full=' + full + ']').addClass('active').find('.btn-date').attr('title', '선택됨'); } $('.jsCalendar').fadeIn(100, function(){ jsCalendarLayer(); jsCalendarLayer(); $(this).find('.calendar_inner').focus(); }); }); } var cIdx = Number($('.jsCalendar').attr('idx')); var cYear = Number($('.jsCalendar').attr('idx-year')); var cMonth = Number($('.jsCalendar').attr('idx-month')); calendarIdx = cIdx; calendarIdxYear = cYear; calendarIdxMonth = cMonth; selDate(); }); /* 다른곳 클릭시 달력 닫기 */ $(document).mouseup(function(e){ var $calendar = $('.jsCalendar, .jsDateForm'); if(!$calendar.is(e.target) && $calendar.has(e.target).length === 0){ $('.jsDateForm.active').removeClass('active'); $('.jsCalendar').fadeOut(100, function(){ $(this).css('opacity', '0'); $(this).removeClass('btm'); }); } }); //날짜 및 버튼 셋팅 function selDate(){ var selDate = $('.jsCalendar').attr('select'); var focus = $('.jsCalendar').attr('focus'); $('.jsCalendar .' + focus).focus(); $('.jsCalendar td[full=' + selDate + ']').addClass('active').find('.btn-date').attr('title', '선택됨'); //오늘 이전 선택 불가 if($('.jsDateForm.active').hasClass('disabledPrev')){ $('.jsCalendar .calendar_table td.today').prevAll('td').find('.btn-date').prop('disabled', true); $('.jsCalendar .calendar_table td.today').closest('tr').prevAll('tr').find('.btn-date').prop('disabled', true); } //오늘 이후 선택 불가 if($('.jsDateForm.active').hasClass('disabledNext')){ $('.jsCalendar .calendar_table td.today').nextAll('td').find('.btn-date').prop('disabled', true); $('.jsCalendar .calendar_table td.today').closest('tr').nextAll('tr').find('.btn-date').prop('disabled', true); } //이전, 다음 개월수 제한 if($('.jsDateForm[min-month]').hasClass('active') || $('.jsDateForm[max-month]').hasClass('active')){ $('.jsCalendar .info_btn').prop('disabled', false); var minMonth = $('.jsDateForm.active').attr('min-month'); var maxMonth = $('.jsDateForm.active').attr('max-month'); var setDate = new Date(tYear, tMonth - minMonth, tDate).getDate(); if(tDate == setDate){ var calendarIdxBefore = calendarIdxYear + calendarIdxMonth; }else{ var calendarIdxBefore = calendarIdxYear + (calendarIdxMonth - 1); } var calendarIdxAfter = calendarIdxYear + calendarIdxMonth; if(Number(minMonth) + calendarIdxBefore < 12){ $('.btn_year_prev').prop('disabled', true); if(Number(minMonth) + calendarIdxBefore == 0){ $('.btn_month_prev').prop('disabled', true); //날짜 disabled if(tDate == setDate){ var setYear = $('.jsCalendar').attr('year'); var setMonth = Number($('.jsCalendar').attr('month')) + 1; var setFull = setYear + '' + setMonth + '' + ('0' + tDate).slice(-2); $('.jsCalendar td[full=' + setFull + ']').find('.btn-date').prop('disabled', true); $('.jsCalendar td[full=' + setFull + ']').prevAll('td').find('.btn-date').prop('disabled', true); $('.jsCalendar td[full=' + setFull + ']').closest('tr').prevAll('tr').find('.btn-date').prop('disabled', true); } } } if(Number(maxMonth) - calendarIdxAfter < 12){ $('.btn_year_next').prop('disabled', true); if(Number(maxMonth) - calendarIdxAfter == 0){ $('.btn_month_next').prop('disabled', true); //날짜 disabled if(tDate == setDate){ var setYear = $('.jsCalendar').attr('year'); var setMonth = Number($('.jsCalendar').attr('month')) + 1; var setFull = setYear + '' + ('0' + setMonth).slice(-2) + '' + ('0' + tDate).slice(-2); $('.jsCalendar td[full=' + setFull + ']').find('.btn-date').prop('disabled', true); $('.jsCalendar td[full=' + setFull + ']').nextAll('td').find('.btn-date').prop('disabled', true); $('.jsCalendar td[full=' + setFull + ']').closest('tr').nextAll('tr').find('.btn-date').prop('disabled', true); } } } } } } /* 달력레이어 위치값 */ function jsCalendarLayer(){ if($('.jsDateForm').hasClass('active')){ $('.jsCalendar').each(function(){ var oTop = $(this).offset().top; var hei = $(this).outerHeight(); var winH = $(window).height(); var sTop = $(window).scrollTop(); var boxH = $('.jsDateForm.active').outerHeight(); var top = Number($('.jsDateForm.active').offset().top) + boxH; var posBtm = (winH + sTop) - Number($('.jsDateForm.active').offset().top); var left = $('.jsDateForm.active').offset().left; //캘린더 위치값 if(top + hei >= winH + sTop){ $(this).addClass('btm').css({ 'top':'auto', 'bottom':posBtm, 'left':left, 'opacity':'1' }); }else{ $(this).removeClass('btm').css({ 'top':top - sTop, 'bottom':'auto', 'left':left, 'opacity':'1' }); } }); } }