Va.MonthPicker — 년-월을 선택하는 캘린더 팝업
년도만 다루는 Va.YearPicker와 년-월-일을 다루는 Va.DatePicker의 중간 자리를 차지하는 컴포넌트입니다. 팝업엔 특정 년도의 12개월 격자가 표시되고, 좌우 화살표로 년도를 이동합니다. 월별 매출·월별 통계 필드에 정확히 어울려요.
- 클래스: Va.MonthPicker — va_component.js:5947
- short name: monthPicker
- 상속: Va.PureField (YearPicker·DatePicker와 형제)
- isContainer: true
- 베이스 CSS: va-monthpicker (팝업 va-menu-pop, calendar-inner)

1. 기본 사용
{
tagName: 'monthPicker',
value: '202412', // YYYYMM 6자리
onSelect: 'onMonthChange'
}
- 화면 표시: 2024-12
- 저장 값(getValue()): 202412
- 팝업: 12개월 격자 + 위쪽 화살표로 년도 이동
2. Va.YearPicker / Va.DatePicker와의 차이
항목Va.YearPickerVa.MonthPickerVa.DatePicker
| 입력 대상 | 년 (4자리) | 년-월 (6자리) | 년-월-일 (8자리) |
| 저장 값 | '2024' | '202412' | '20241225' |
| 팝업 UI | 10년 격자 | 12개월 격자 | 일 단위 캘린더 |
| 마스킹 | 없음 | ____-__ | ____-__-__ |
| 화살표 이동 | 10년씩 | 1년씩 | 1개월씩 |
| 오늘 버튼 | ✕ | ✓ (이번 달로 이동) | ✓ (오늘로) |
| popWidth 기본 | 240 | 240 | 260 |
한 줄 요약: "년-월 단위로 필요할 때의 정답. 월간 리포트·분기 통계·월별 예산."
3. 주요 속성
날짜 포맷
속성기본값설명
| dateFormat | 'ym' | 화면 순서 — ym (년-월) / my (월-년) |
| dateSeperator | '-' | 화면 구분자 |
| valueDateFormat | 'ym' | 저장 값 순서 |
| valueDateSeperator | '' | 저장 값 구분자 (기본 없음) |
| masking | 자동 (____-__ 또는 __-____) | dateFormat에 따라 자동 |
핵심 개념 — DatePicker와 동일한 화면/저장 값 분리:
{
tagName: 'monthPicker',
dateFormat: 'my', // 화면: 12-2024
dateSeperator: '-',
valueDateFormat: 'ym', // 저장: 202412 (서버가 원하는 형태)
valueDateSeperator: ''
}
팝업
속성기본값설명
| popWidth | 240 | 팝업 폭 |
| expanded | false | 초기 상태 |
PureField 상속
value, placeholder, readonly, disabled, size, appearance, stopPropagation 등 표준.
4. 날짜 포맷 조합 예시
한국 표준
{ tagName: 'monthPicker', value: '202412' }
// 화면: 2024-12
// 저장: 202412
미국식 표시
{
tagName: 'monthPicker',
dateFormat: 'my',
dateSeperator: '/',
valueDateFormat: 'ym'
}
// 화면: 12/2024
// 저장: 202412
서버가 하이픈 포함 원할 때
{
tagName: 'monthPicker',
valueDateSeperator: '-',
value: '2024-12'
}
// 화면: 2024-12
// 저장: 2024-12
5. 이벤트
이벤트시그니처발생 시점
| select | (component, element, value, evt) | 팝업에서 월 클릭 시 |
| beforePop / afterPop / hidePop | 팝업 표시/숨김 | |
| expand / collapse | 팝업 확장/축소 | |
| focus / blur | 표준 |
6. 메서드 — 두 벌의 setter/getter
DatePicker·DateTimePicker와 같은 패턴:
메서드설명
| setValue(value) | valueDateFormat 규약 값 세팅 (서버에서 받은 값을 세팅할 때) |
| getValue() | valueDateFormat 규약으로 반환 (서버 전송용) |
| setRawValue(value) | 항상 YYYYMM 원시 값 세팅 (내부용) |
| getRawValue() | 항상 YYYYMM 원시 값 반환 (내부용) |
동작 흐름:
- setValue('202412') → 내부 저장은 YYYYMM → 화면은 dateFormat/dateSeperator로 변환 표시
- getValue() → 화면 값 파싱 → valueDateFormat/valueDateSeperator에 맞춰 반환
팝업 제어
메서드설명
| showMonthPickerPop(evt) / hideMonthPickerPop() | 팝업 강제 열기/닫기 |
| showPop() / expand() | drawCalendar() 호출 (레거시 별칭) |
| hidePop() / collapse() | 팝업 숨김 |
| drawCalendar(value) | 팝업 내부 렌더링 |
상태
메서드설명
| setDisabled(bool) / setReadOnly(bool) | PureField 상속 |
| focus() / blur() | 포커스 |
7. 팝업 UI 구조
drawCalendar()가 렌더링:
┌─────────────────────────────┐
│ ← 2024 → │ ← 헤더 (년도 표시, ←→로 년도 이동)
├─────────────────────────────┤
│ 1월 2월 3월 │
│ 4월 5월 6월 │
│ 7월 8월 9월 │ ← 3×4 격자 (12개월)
│ 10월 11월 12월 │
├─────────────────────────────┤
│ 오늘 │ ← "오늘" 버튼 (이번 달로 이동)
└─────────────────────────────┘
- 년도 이동 (← / → 버튼) — 1년씩
- 12개월 버튼 격자 — 클릭 시 select 이벤트 발생 + 팝업 닫힘
- 오늘 버튼 — 현재 년-월로 즉시 이동 (Va.Util.getNowYearMonth())
8. 내부 구조
<div elname="element" class="va-monthpicker [size]..." tag-name="monthPicker" field="true">
<div elname="fieldWrapper" class="field-wrapper">
<input elname="field" type="text" placeholder="____-__" style="border:0px">
<div elname="focusLine" class="focus-line"></div>
<div elname="calendarIconWrapper">
<span elname="calendarIcon" class="icon menu ico_calender_ltr">📅</span>
</div>
</div>
<div elname="popDiv" class="menu-button-pop-div">
<div elname="pop" class="va-menu-pop" style="position:absolute; display:none">
<div elname="popInner" class="calendar-inner">
<div class="date-picker-pop-header">← 2024 →</div>
<!-- 12개월 격자 -->
<div class="date-picker-pop-bottom">
<button>오늘</button>
</div>
</div>
</div>
</div>
</div>
9. 팝업 상태머신 연동
프레임워크 공용 팝업 상태머신 참여:
- Va.addAutoHide(this.popElement) — 외부 클릭 시 자동 닫힘
- Va.hideOtherComponents(this) — 다른 팝업 자동 닫음
- getHiddenAreaElement()로 팝업 이동 → 부모 stacking 회피
- 뷰포트 넘침 시 위로 자동 뒤집기
10. 언제 쓰나
MonthPicker가 맞을 때
- 월별 매출·통계 리포트 필터
- 월별 예산 등록
- 월간 근태·급여 대상 월 선택
- 분기 통계 (월을 선택해 소속 분기 파악)
- 년-월 단위로 데이터가 관리되는 모든 상황
다른 걸 쓸 때
- 년도만 필요 → Va.YearPicker
- 년-월-일 필요 → Va.DatePicker
- 시간까지 → Va.DateTimePicker
- 라벨 붙은 폼 필드 → Va.MonthField
- 년-월 콤보 UI (드롭다운 두 개) → Va.ComboboxField 조합
- 특정 월 목록만 (예: 최근 6개월) → Va.ComboboxField
11. 흔한 조합 예시
// 한국 표준
{ tagName: 'monthPicker', value: '202412' }
// 미국식 표시
{
tagName: 'monthPicker',
dateFormat: 'my',
dateSeperator: '/',
valueDateFormat: 'ym',
value: '202412' // 화면: 12/2024
}
// 서버가 하이픈 포함 원할 때
{
tagName: 'monthPicker',
valueDateSeperator: '-',
value: '2024-12'
}
// 오늘 년-월로 초기화
mounted() {
const now = new Date();
const ym = now.getFullYear() +
String(now.getMonth() + 1).padStart(2, '0');
this.getRef('month').setValue(ym);
}
// 넓은 팝업
{
tagName: 'monthPicker',
popWidth: 300,
value: '202412'
}
12. 알아두면 좋을 주의사항
- value는 6자리 문자열 — '202412' 형태. Date 객체 넘기면 .substring 호출에서 크래시.
- setValue()는 value.replaceAll 사용 — null이나 숫자 넘기면 크래시. 문자열 확실히.
- getValue()는 문자열 반환 — 빈 값일 땐 ''.
- dateFormat과 valueDateFormat 혼동 주의 — 화면 vs 저장.
- 마스킹 자동 — dateFormat에 따라 자동. 사용자 지정 시 덮어씀.
- 필드에 잘못된 년월 타이핑 가능 — 마스킹은 자릿수만 강제. 9999-99 같은 값도 입력 가능. 별도 검증 필요.
- popWidth 기본 240 — DatePicker(260)보다 작음. 12개월 격자엔 충분.
- ym / my 외 다른 포맷 없음 — 년-일 조합 등은 미지원.
- 팝업 상태머신 참여 — 다른 팝업과 자동 상호 배타.
- 초기값 없으면 오늘 년-월 — drawCalendar()가 Va.Util.getNowYearMonth()로 fallback.
- timezone 처리 있음 — 코드에 KST 오프셋 계산 있어 한국 시간대 기준. UTC 정확도가 중요하면 별도 확인.
- 오늘 버튼은 이번 달로 이동만 — 자동 선택은 아님. 클릭해야 확정.
13. 실전 예 — 월별 매출 조회
class MonthlySales extends Va.View {
mounted() {
// 지난 달로 초기화
const now = new Date();
now.setMonth(now.getMonth() - 1);
const lastMonth = now.getFullYear() +
String(now.getMonth() + 1).padStart(2, '0');
this.getRef('month').setValue(lastMonth);
this.loadSales(lastMonth);
}
onMonthSelect(picker, el, value, evt) {
this.loadSales(value);
}
loadSales(yyyymm) {
SalesService.getMonthly(this, { yyyymm }, (view, ok, res) => {
if (ok) view.getRef('grid').setData(res.data.list);
});
}
config() {
return {
tagName: 'page',
tags: [{
tagName: 'panel',
tags: [
{ tagName: 'h2', innerHTML: '월별 매출' },
{
tagName: 'div',
layout: 'ds-flex fd-row ai-center gap-s',
tags: [
{ tagName: 'label', innerHTML: '대상 월:' },
{
tagName: 'monthPicker',
ref: 'month',
onSelect: 'onMonthSelect',
style: { width: '150px' }
}
]
},
{
tagName: 'grid',
ref: 'grid',
columns: [
{ key: 'day', title: '일', width: 60 },
{ key: 'revenue', title: '매출', fillRatio: 1 },
{ key: 'orders', title: '건수', width: 100 }
]
}
]
}]
};
}
}
14. MonthField가 필요하면
라벨·검증까지 필요한 폼 필드로 쓰려면 Va.MonthField (Field 계열 래퍼)를 사용하세요:
{
tagName: 'monthField',
label: '대상 월',
value: '202412',
required: true
}
DateField·YearField와 같은 Composition 패턴으로, 내부에 Va.MonthPicker를 소유합니다.
'컴포넌트 > 필드 컴포넌트' 카테고리의 다른 글
| TimePicker (시각선택) (0) | 2026.09.12 |
|---|---|
| MonthField (년월필드) (0) | 2026.09.12 |
| YearField (연도필드) (1) | 2026.09.11 |
| YearPicker (연도선택) (0) | 2026.09.11 |
| DateTimeField (일시필드) (0) | 2026.09.11 |