목적
현재 개발 중인 서비스에는 날짜 입력 Input이 굉장히 많다.
그렇기 때문에 공통 컴포넌트를 생성하여 반복적인 코드를 줄이고 스타일 통일성을 가져가려 했다.
필요 기능
우선 내가 만들려고 하는 CommonDate 컴포넌트에 필요한 기능은 다음과 같다.
- Date Picker
- 사용자 직접 입력
- YYYY-MM-DD 형식의 날짜 포매팅
- 날짜 유효성 검사
- 선택 불가능한 날짜 disable 처리
개발
구조
quasar의 공식 문서를 참고하여 구조를 가져갔다.
<q-input>
<template #append>
<q-icon />
<q-popup-proxy>
<q-date />
</q-popup-proxy>
</template>
</q-input>
Date Picker 한국어 적용
quasar의 기본 Date Picker의 경우 요일이나 월 표시가 전부 영어로 되어있다.
이 상태 그대로 우리 서비스에 적용하기에는 이질감이 크다고 생각해 한글로 바꾸었다.
이때 사용할 것은 q-date의 locale 속성
const koLocale = {
days: '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),
daysShort: '일_월_화_수_목_금_토'.split('_'),
months: '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'),
monthsShort: '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'),
};
출력할 형식에 맞춰 작성해주었다.
문자열로 적고 split 메서드로 분리해주었지만, 사실 예시처럼 배열로 써도 무방하다.
<q-date :locale="koLocale" />
사용자 직접 입력
이것을 위해 구조를 위와 같이 설정한 것이다.
이때 사용자가 입력하는 값과 Date Picker로 선택한 값은 어차피 같은 값이기 때문에 동일한 변수를 바인딩해주어야 한다.
<q-input v-model="date" >
...
<q-date v-model="date />
...
</q-input>
공통 컴포넌트이기 때문에 실제 변수는 해당 컴포넌트를 불러서 사용하는 컴포넌트에 존재하고, CommonDate에는 props로 내려주어야 한다.
그러나 props로 내린 변수는 v-model에 직접 적용할 수 없기 때문에 computed를 활용하였다.
const props = defineProps<DateProps>();
const emit = defineEmits(['update:date', 'request:date']);
const isValid = ref(true);
const date = computed({
get: () => {
return props.value?.length ? props.value : '';
},
set: (value) => {
emit('update:date', value);
},
});
computed의 get을 이용하여 v-model에 바인딩할 date 변수를 할당하였고, set을 이용하여 상위 컴포넌트에 실제 변수 변경을 위한 emit 이벤트를 전달하였다.
날짜 포매팅
q-input 또는 q-date의 mask 속성을 활용
<q-date mask=”YYYY-MM-DD” />
그러나 이때 q-input의 mask="date" 를 적용하게 되면 q-date의 mask와 충돌하여 원하는 결과가 적용되지 않았다.
그 이유는 mask=”date” 는 YYYY/MM/DD 스타일이기 때문이다.
그러나 사용자 입력 시에도 적절한 mask를 걸어주는 것이 필요했고, 그렇기때문에 quasar의 숫자 마스킹 룰인 #을 사용했다.
<q-input mask="####-##-##" />
날짜 유효성 검사
Date Picker를 이용해 날짜를 선택하는 경우 올바르지 않은 날짜 형식을 입력할 가능성이 없지만, 사용자 직접 입력의 경우 9999-99-99처럼 올바르지 않은 날짜 값을 입력할 수 있다.
이러한 경우에 에러 표시와 tooltip을 띄우도록 하였다.
(→ tooltip은 이후 삭제 처리)
q-input의 rules 속성 이용
rules에 적용할 판단식을 작성해주면 된다.
<q-input
:rules="[handleDate]"
hide-bottom-space
>
const handleDate = () => {
if (data.value === '') return true;
isValid.value = /^(?:\\d{4})-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])$/.test(
date.value,
);
return isValid.value;
};
정규표현식을 활용하여 적절한 날짜 값(월: 1~12, 일: 1~31)인지 확인해주었고, 사용자 입력 전에 유효성 검사를 하여 에러를 뱉어내는 것을 방지하고자 if문을 추가하였다.
또한 이때 기본 q-input은 에러 메시지를 input 박스 하단에 작성한다. 그렇게 되면 유효성 검사를 통과하지 못했을 때 하단 여백이 생기면서 다른 요소들과의 거리, 배치 등을 해치게 되었다.
그래서 hide-bottom-space 속성을 추가하여 하단 공간이 생겨나지 않도록 하였다.
Date Picker 선택 불가능한 날짜 disable 처리
q-date의 options
<q-date :options="optionsFn" />
/**
* 선택 가능한 날짜 제한
* - 오늘 이후 날짜 (기준일자를 기준으로 수정 필요)
* - 이전 날짜 중 주말, 공휴일
*/
const optionsFn = (date: string) => {
const stdDateFormat = store.stdDate.replaceAll('-', '/');
const stdDate = new Date(stdDateFormat);
const selectedDate = new Date(date);
const year = selectedDate.getFullYear(); // 연
const month = leftPad(selectedDate.getMonth() + 1); // 월
const day = leftPad(selectedDate.getDate()); // 일
const selectedDateFormat = [year, month, day].join('-'); // 구분자 -을 넣은 string
// 날짜 제한 리스트에 존재하는지 판단(앞에 not연산자로 isAllowed에 맞게 조정)
const isAllowed = !store.limitDateList.includes(selectedDateFormat);
return props.limitDate
? selectedDate <= stdDate && selectedDateFormat >= '2021-12-01' && isAllowed
: true;
};
option에 적용하는 함수는 date picker가 가리키고 있는 달의 모든 날을 검사하여 각 날짜의 boolean 결과 값에 따른 disable 처리를 해준다.
결과물
[ 참고 자료 ]
'Quasar' 카테고리의 다른 글
[ Quasar ] q-select에 placeholder 적용하기 (0) | 2024.05.16 |
---|---|
[ Quasar ] q-select 옵션 검색 API debounce 적용 | 한국어 입력 오류 해결 (0) | 2024.03.28 |
[ Quasar ] q-input mask 적용 후 입력 값 삭제 시 커서 이동 버그 (0) | 2024.03.27 |
[ Quasar ] q-input mask로 숫자 포매팅 (0) | 2024.03.27 |
[ Quasar ] q-input validate 메서드 파헤치기 (0) | 2024.03.27 |