기본 콘텐츠로 건너뛰기

vuejs에서 달력 플러그인(flatpickr)을 component 로 사용 시. 시작일, 종료일 지정하기 - vuejs

vuejs (3.0)에서 달력 플러그인(flatpickr)을 component로 사용 할 때 시작일, 종료일 지정하기


.vue

<flat-pickr class="input_cal trans calStr" placeholder="시작일" readonly
     v-model="info.sdate"
     @on-change="stChange"
     :config="config('st')" />
<flat-pickr class="input_cal trans calEnd" placeholder="종료일" readonly
     v-model="info.edate"
     @on-change="edChange"
     :config="config('ed')" />
<flat-pickr class="input_cal trans calToay" placeholder="오늘" readonly
     v-model="info.today"
     :config="configtoday" />

javascript

<script setup>
import { ref, computed, nextTick } from "vue";
import flatPickr from "vue-flatpickr-component";
import "flatpickr/dist/flatpickr.min.css";
import dayjs from "dayjs";

const info = ref({
  sdate:"",// 시작일
  edate:"",// 종료일
  today:"", 
});

// 달력 config
const config = computed(() => {
  return (no) => {
    let conf = null;
    // 시작일.  종료일 제한
    if(no === "st") {
      conf = {
        maxDate: order.value.edate,
        locale: {
          months: {
            shorthand:["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
            longhand: ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]
          },
          weekdays: {
            shorthand: ["일", "월", "화", "수", "목", "금", "토"],
            longhand: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
          }
        }
      }
    }
    // 종료일.  시작일 제한
    else {
      conf = {
        minDate: order.value.sdate,
        locale: {
          months: {
            shorthand:["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
            longhand: ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]
          },
          weekdays: {
            shorthand: ["일", "월", "화", "수", "목", "금", "토"],
            longhand: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
          }
        }
      }
    }
    return conf;
  }
})

// 달력이 하나일 때
const configtoday = ref();
nextTick( () => {
  configtoday.value = {
    locale: {
      months: {
        shorthand: ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"],
        longhand: ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]
      },
      weekdays: {
        shorthand: ["일", "월", "화", "수", "목", "금", "토"],
        longhand: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
      }
    }
  }
})

// 달력 관련
const stChange = (selectDates, dateStr, instance) => {
  info.value.sdate = dateStr;
}
const edChange = (selectDates, dateStr, instance) => {
  info.value.edate = dateStr;
}

// dayjs 사용시
// info.today = dayjs(new Date(), "YYYY-MM-DD").format();
</script>

component(ex: Calendar.vue)

<template>
  <div class="m_calendar_ar">
    <button class="btn_ar" @click="arrowDay('prev')">◀</button>
    <div class="m_calendar">
      <flat-pickr type="text" class="input_cal trans calStr" placeholder="시작일" readonly v-model="info.today" :config="config" @on-change="checkDay" />
    </div>
    <button class="btn_ar" @click="arrowDay('next')">▶</button>
  </div>
</template>

<script setup>
import { ref, nextTick } from "vue";
import flatPickr from "vue-flatpickr-component";
import "flatpickr/dist/flatpickr.min.css";
import dayjs from "dayjs"

// 달력 정보
const info = ref({
  today: "",//
  prevBasicDay: "",// 이전 버튼 클릭 시 선택된 날짜용
  nextBasicDay: "",// 다음 버튼 클릭 시 선택된 날짜용
})
const config = ref();

//
nextTick(() => {
  info.value.today = new Date();
  config.value = {
    disableMobile: true,
    dateFormat: "Y년 n월 j일",// y, m, d
    locale: {
      months: {
        shorthand: ["01월", "02월", "03월", "04월", "05월", "06월", "07월", "08월", "09월", "10월", "11월", "12월"],
        longhand: ["01월", "02월", "03월", "04월", "05월", "06월", "07월", "08월", "09월", "10월", "11월", "12월"]
      },
      weekdays: {
        shorthand: ["일", "월", "화", "수", "목", "금", "토"],
        longhand: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
      }
    }
  }
})

// 지난 날, 다음 날
const arrowDay = (n) => {
  if(n === "prev") {
    info.value.prevBasicDay = info.value.today.replace(/년|월|일/g, "").replace(/ /g, "-");
    let prevday = dayjs(info.value.prevBasicDay).add(-1, "day").format("YYYY년 M월 DD일");
    info.value.today = prevday
  } else {
    info.value.nextBasicDay = info.value.today.replace(/년|월|일/g, "").replace(/ /g, "-");
    let nextday = dayjs(new Date(info.value.nextBasicDay)).add(1, "day").format("YYYY년 M월 DD일");
    info.value.today = nextday
  }
}

const checkDay = (selectedDates, dateStr, instance) => {
  info.value.today = dateStr;
  emit("today", info.value.today);
}

// 바뀐 날짜 부모 컴포넌트에 보내기
const emit = defineEmits(["today"]);
</script>
<!--
  // 부모 컴포넌트에서 사용 시
  <Calendar @today="checkDay" />
  ...
  const checkDay = (value) => {
    console.log("today : ", value);
  }
 -->


component(ex: BoxCalendar.vue) ...

<template>
  <div class="box_calendar">
    <p class="txt">{{ txt }}</p>
    <img src="@/assets/images/icon_calendar_small.svg" alt="">
    <flat-pickr type="text" class="cal_input trans calStr" :placeholder="txt"
        v-model="cal.checkday" :config="config" @on-change="checkDay" />
  </div>
</template>

<script setup>
import { ref, computed, nextTick } from "vue";
import flatPickr from "vue-flatpickr-component";
import "flatpickr/dist/flatpickr.min.css";
import dayjs from "dayjs"

// 바뀐 날짜 부모 컴포넌트에 보내기
const emit = defineEmits(["checkday"]);

//
const props = defineProps({
  txt: {
    type: String,
    defatult: undefined
  },
  day: undefined,
  maxday: null,// 선택 가능한 마지막 날짜
  minday: null,// 선택 가능한 최초 날짜
})

//
const cal = ref({
  checkday: "",//
  maxday: computed(() => {
    return props.maxday
  }),
  minday: computed(() => {
    return props.minday
  }),
})

if(props.day === undefined) {
  cal.value.checkday = new Date();
} else {
  cal.value.checkday = props.day;
}

//
const config = computed(() => {
  return {
    disableMobile: true,
    dateFormat: "Y년 m월 j일",// y, n, d
    
    maxDate: cal.value.maxday,///
    minDate: cal.value.minday,///
    /// mode: "range",
    
    locale: {
      /// rangeSeparator : ' ~ ',
      months: {
        shorthand: ["01월", "02월", "03월", "04월", "05월", "06월", "07월", "08월", "09월", "10월", "11월", "12월"],
        longhand: ["01월", "02월", "03월", "04월", "05월", "06월", "07월", "08월", "09월", "10월", "11월", "12월"]
      },
      weekdays: {
        shorthand: ["일", "월", "화", "수", "목", "금", "토"],
        longhand: ["일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"],
      }
    }
  }
});

const checkDay = (selectedDates, dateStr, instance) => {
  cal.value.checkday = dateStr;
  emit("checkday", cal.value.checkday);
}

</script>
<!--
  # day : 보여지는 날짜(없으면 오늘 날짜)
  # maxday : 시작일 달력에서 선택 가능한 마지막 날짜
  # minday : 종료일 달력에서 선택 가능한 최초 날짜
  @ checkday : 바뀐 날짜를 부모로 전달

  // 부모 컴포넌트에서 사용 시(단일)
  <BoxCalendar txt="타이틀" :day="보여지는 날짜" @checkday="바뀐 날짜 받는 함수" />
  ...
  const 바뀐 날짜 받는 함수 = (value) => {
    console.log("checkday : ", value);
  }

  // 부모 컴포넌트에서 사용 시(시작일 ~ 종료일)
  <BoxCalendar txt="시작일타이틀" :day="cal.startday"
      :maxday="cal.endday" @checkday="cal.startday = $event" />
  <BoxCalendar txt="종료일타이틀" :day="cal.endday"
      :minday="cal.startday" @checkday="cal.endday = $event" />
 -->


component(ex: RangeCalendar.vue) ...

<template>
  <flat-pickr class="input_cal trans calStr" :config="config()" readonly v-model="info.rangedate" />
  <a href="#" id="movefocus" class="hidden"></a>
</template>

<script setup>
import { ref, computed } from "vue"
import dayjs from "dayjs"
import flatPickr from "vue-flatpickr-component"
import "flatpickr/dist/flatpickr.min.css"

//
const emit = defineEmits(["range"])

//
const props = defineProps({
  maxday: null, // 선택 가능한 마지막 날짜
  rangedate: null,
  customrange: false, // true로 수정되면 1주일전 고정이 아니라 임의의 기긴을 선택할 수 있게 변경
})

//
const info = ref({
  maxday: computed(() => {
    return props.maxday
  }),
  rangedate: ""
})

info.value.rangedate = props.rangedate;

//
const config = computed(() => {
  return () => {
    let conf = null;
    conf = {
      disableMobile: true,
      mode: "range",
      maxDate: info.value.maxday,
      locale: {
        rangeSeparator: ' ~ ',
        months: {
          shorthand: ['01월', '02월', '03월', '04월', '05월', '06월', '07월', '08월', '09월', '10월', '11월', '12월'],
          longhand: ['01월', '02월', '03월', '04월', '05월', '06월', '07월', '08월', '09월', '10월', '11월', '12월']
        },
        weekdays: {
          shorthand: ['일', '월', '화', '수', '목', '금', '토'],
          longhand: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일']
        }
      },
      onChange: function(selectedDates, dateStr, instance) {
        if(!props.customrange) {
          // 날짜 한 번 클릭하면 6일전 날짜를 시작날짜로 추가
          selectedDates.unshift(new Date(dayjs(selectedDates).add(-6, "days")));

          //
          info.value.rangedate = dayjs(selectedDates[0]).format("YYYY-MM-DD") + " ~ " + dayjs(selectedDates[1]).format("YYYY-MM-DD");

          emit("range", info.value.rangedate);

          // 날짜 바꾼 달력 다시 클릭 시 바로 클릭이 안되고 다른데 클릭했다가 클릭해야 클릭되는 현상 때문에 focus를 다른데로 이동
          setTimeout(() => {
            document.querySelector("#movefocus").focus();
          }, 70);
        } else {
          if(selectedDates[1] !== undefined) {
            info.value.rangedate = dayjs(selectedDates[0]).format("YYYY-MM-DD") + " ~ " + dayjs(selectedDates[1]).format("YYYY-MM-DD");

            emit("range", info.value.rangedate);
          }
        }
      }
    }
    return conf
  }
})
</script>
<!--
  # maxday : 달력에서 선택 가능한 마지막 날짜
  # rangedate : 선택한 기간

  // 컴포넌트에서 사용 시
  <RangeCalendar :rangedate="info.rangedate" @range="rangeDate" />
  <RangeCalendar :rangedate="info.rangedate" @range="rangeDate" :customrange="true" />

  ...
  import dayjs from "dayjs"
  ...
  const info = ref({
    rangedate: `${dayjs(new Date()).add(-6, "day").format("YYYY-MM-DD")} ~ ${dayjs(new Date()).format("YYYY-MM-DD")}`
  })
  ...
  const rangeDate = (e) => {
    info.value.rangedate = e;
    console.log(info.value.rangedate);
  }
 -->

날짜가 변경되면 set(option, value)을 이용해서 다른 달력의 옵션을 설정하는 cdn 형태와는 다르게 컴포넌트에서는 :config="config" 를 사용해서 다른 달력의 옵션을 설정할 수 있다


끝.