Frond-end/Vue
[트러블슈팅/ Vue3] 컴포넌트에 데이터 바인딩이 되지 않는 문제(feat. ref, watch)
Nellie Kim
2024. 3. 25. 12:24
728x90
문제 상황
달력 컴포넌트(ExampleFull)에 날짜와 타입을 전달하여, 달력에 보여주고 싶었다.
26일자에 '입원'이라는 문구가 떠야하는데 아래와 같이 보였다.
기존의 일정 list 뷰 코드
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { RETURN_CODE } from '@/apis/common'
import { ReserveModel, ReserveScheduleModel, getReserveScheduleList } from '@/apis/reserve'
import { useRouter } from 'vue-router'
import { Dialog } from '@varlet/ui'
/**
|--------------------------------------------------
| 😃 1. 변수
|--------------------------------------------------
*/
const isRefresh = ref(false)
const data = ref<ReserveModel>({} as ReserveModel)
const scheList = ref<ReserveScheduleModel[] | undefined>() // 예약 데이터 안의 reserveScheduleList
const router = useRouter()
const bottom = ref(false)
const isPopup = ref(false)
const reserveType = ref<any>('')
const reserveDate = ref<any>('')
const patientData = ref<any>('')
/**
|--------------------------------------------------
| 🔑 2. 일반 함수
|--------------------------------------------------
*/
/** 1. 상세페이지로 이동하는 함수 */
// function goToDetail(idx: any) {
// if (idx !== undefined) {
// // 상세페이지 이동
// router.push(`/hospital/checkinout/${idx}`)
// } else {
// // ID가 없는 경우 처리할 로직 추가
// console.error('Item ID is undefined!')
// }
// }
function goToDetail() {
isPopup.value = true
console.log('ddddddd')
}
function goToDetail2() {
isPopup.value = true
openPopup()
console.log('ddddddd')
}
/** .
* 토큰 확인 함수 */
function tokenError(code: string) {
if (/^30002\d{3}$/.test(code)) {
Snackbar.error('로그인 후 이용 부탁드립니다')
router.replace('/login')
}
}
/** 3. 새로고침 함수 */
function handleRefresh() {
isRefresh.value = false
}
/** 8. 팝업을 오픈하는 함수 */
function openPopup() {
Dialog({
title: '2024.10.10',
message: '건강검진'
})
}
/**
|--------------------------------------------------
| 🎁 3. fetch 함수
|--------------------------------------------------
*/
/**------------------------
| 🎈 fetch 함수 1
|------------------------*/
/** 1. 예약 스케줄 리스트 조회 호출 */
async function fetchData() {
const params = {
reserveType: 'INPATIENT' // 입원 예약 환자만 조회
} as ReserveModel
if (history.state.type) params.reserveType = history.state.type
if (history.state.type) params.reserveDt = history.state.date
const response = await getReserveScheduleList(params)
if (response.code !== RETURN_CODE.SUCCESS) {
console.log('예약 정보를 가져오는 중 오류가 발생했습니다.')
return
}
tokenError(response.code)
data.value = response.data
patientData.value = data.value
scheList.value = data.value.reserveScheduleList
console.log('data,,,,,', data.value)
console.log('data,,,,,예약일 :: ', data.value.reserveDt)
let dateString = data.value.reserveDt?.toString()
reserveDate.value = dateString?.slice(8, 10)
console.log('data,,,,,프롭스용 예약일 :: ', reserveDate.value) // 출력: 29
console.log('data,,,,,프롭스용 예약타입 :: ', data.value.reserveType)
reserveType.value = data.value.reserveType
console.log('reserveScheduleList,,,,,,', scheList.value)
}
/**
|--------------------------------------------------
| 🎁 4. LifeCycle 함수
|--------------------------------------------------
*/
onMounted(() => {
fetchData()
})
</script>
<!-- /**
|--------------------------------------------------
| 🎨 화면
|--------------------------------------------------
*/ -->
<template>
<div class="message">
<var-pull-refresh v-model="isRefresh" @refresh="handleRefresh">
<app-header title="일정">
<template #left>
<app-back />
</template>
<template #right>
<app-side-menu />
</template>
</app-header>
<div class="message-list">
<div class="message-item">
<div class="message-item-detail">
<div class="message-item-detail-header-centered-box">
<var-paper>{{ data?.patientName }}님</var-paper>
<var-paper>환자 등록번호 : {{ data?.patientId }}</var-paper>
</div>
<div class="message-item-detail-header-centered-box">
<ExampleFull
:reserveDate="reserveDate"
:reserveType="reserveType"
:data="data"
@toggle-drawer="goToDetail2"
/>
</div>
<div class="message-item-detail-description"></div>
</div>
</div>
</div>
</var-pull-refresh>
</div>
<!-- <TestComponent :reserveDate="reserveDate" :reserveType="reserveType" /> -->
<var-button type="primary" block @click="goToDetail"></var-button>
<router-stack-view />
</template>
<style lang="less" scoped>
.message {
padding: calc(var(--app-bar-height)) 0 0;
&-list {
padding: 3px 0;
}
&-item {
position: relative;
display: flex;
padding-top: 3px;
&-avatar {
flex-shrink: 0;
margin: 0 18px;
}
&-detail {
width: 100%;
border-bottom: thin solid var(--divider-color);
padding-bottom: 5px;
&-header {
display: flex;
justify-content: space-between;
align-items: center;
&-name {
color: var(--app-title-color);
font-size: 16px;
width: 190px;
}
&-date {
color: var(--app-subtitle-color);
font-size: 14px;
margin-bottom: 2px;
}
&-centered-box {
/* 위아래 여백 조절 */
margin: 10px;
padding: 17px;
border: 1.5px solid rgb(222, 218, 218);
border-radius: 10px;
color: rgb(49, 49, 165);
}
}
&-description {
color: var(--app-subtitle-color);
font-size: 15px;
margin-top: 6px;
}
}
}
.var-steps {
margin: 10px;
}
.var-step {
margin: 15px;
}
}
.var-step__vertical-content {
margin: 15px !important;
border: 1.5px solid rgb(222, 218, 218) !important;
border-radius: 10px !important;
}
.var-step__vertical-tag {
margin: 100px !important; /* 원하는 간격을 지정합니다. */
}
</style>
기존의 달력 컴포넌트 뷰
<script setup lang="ts">
// Using the publish version, you would do this instead:
// import { CalendarView, CalendarViewHeader, CalendarMath } from "vue-simple-calendar"
import CalendarView from '../vue-simple-calendar/CalendarView.vue'
import CalendarViewHeader from '../vue-simple-calendar/CalendarViewHeader.vue'
import CalendarMath from '../vue-simple-calendar/CalendarMath'
import { ICalendarItem, INormalizedCalendarItem } from './ICalendarItem'
import { onMounted, reactive, defineEmits } from 'vue'
/**
|--------------------------------------------------
| 😃 1. 변수
|--------------------------------------------------
*/
const date = ref('')
const type = ref('')
// 현재 달을 가져오는 함수 (선택적으로 시간 및 분도 포함)
const thisMonth = (d: number, h?: number, m?: number): Date => {
const t = new Date()
return new Date(t.getFullYear(), t.getMonth(), d, h || 0, m || 0)
}
// 부모 컴포넌트로부터 받은 props 정의
const props = defineProps<{ reserveDate: string; reserveType: string; data: any }>() // 부모Component에서 받은값
console.log('props!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ', props)
console.log('props.reserveDate!!!!!!!!!!!!!!!', date.value)
console.log('props.reserveType!!!!!!!!!!!!!!! ', props.reserveType)
console.log('props.data~~~~~~~~~~~~~~ ~~~~~~ ~~~~ ~~~~~~~~~ ~~~~~ ', props.data)
// 상태 객체를 반응적으로 정의
interface IExampleState {
showDate: Date // 캘린더에 표시되는 날짜
message: string // 상태 메시지
startingDayOfWeek: number // 주의 시작 요일 (0: Sunday, 1: Monday, ..., 6: Saturday)
disablePast: boolean // 과거 날짜 사용 금지 여부
disableFuture: boolean // 미래 날짜 사용 금지 여부
displayPeriodUom: string // 표시 기간 단위 (예: 'month', 'year')
displayPeriodCount: number // 표시 기간 개수
displayWeekNumbers: boolean // 주 번호 표시 여부
showTimes: boolean // 시간 표시 여부
selectionStart?: Date // 선택 시작 날짜
selectionEnd?: Date // 선택 종료 날짜
newItemTitle: string // 새로운 아이템 제목
newItemStartDate: string // 새로운 아이템 시작 날짜
newItemEndDate: string // 새로운 아이템 종료 날짜
useDefaultTheme: boolean // 기본 테마 사용 여부
useHolidayTheme: boolean // 휴일 테마 사용 여부
useTodayIcons: boolean // 오늘 아이콘 사용 여부
items: ICalendarItem[] // 캘린더에 표시되는 아이템 배열
}
const state = reactive({
showDate: thisMonth(1), // 캘린더에 표시할 현재 달의 첫 날짜
message: '', // 상태 메시지
startingDayOfWeek: 0, // 주의 시작 요일 (0: Sunday, 1: Monday, ..., 6: Saturday)
disablePast: false, // 과거 날짜 사용 금지 여부
disableFuture: false, // 미래 날짜 사용 금지 여부
displayPeriodUom: 'month', // 표시 기간의 단위 (예: 'month', 'year')
displayPeriodCount: 1, // 표시할 기간의 개수
displayWeekNumbers: false, // 주 번호 표시 여부
// showTimes: true, // 시간 표시 여부
selectionStart: undefined, // 선택 시작 날짜
selectionEnd: undefined, // 선택 종료 날짜
newItemTitle: '', // 새로운 아이템 제목
newItemStartDate: '', // 새로운 아이템 시작 날짜
newItemEndDate: '', // 새로운 아이템 종료 날짜
useDefaultTheme: true, // 기본 테마 사용 여부
// useHolidayTheme: true, // 휴일 테마 사용 여부
useTodayIcons: true, // 오늘 아이콘 사용 여부
items: [
{
startDate: thisMonth(Number(date.value)), // 아이템 시작 날짜 설정
// title: props.reserveType, // 아이템 제목 설정
title: date.value,
url: 'https://en.wikipedia.org/wiki/Birthday' // 아이템 URL 설정
}
// {
// id: "e11",
// startDate: thisMonth(29),
// title: "수술",
// },
] as ICalendarItem[] // 캘린더에 표시할 아이템 배열
} as IExampleState)
// const userLocale = computed((): string => CalendarMath.getDefaultBrowserLocale())
// const dayNames = computed((): string[] => CalendarMath.getFormattedWeekdayNames(userLocale.value, "long", 0))
// 계산된 속성 정의
const themeClasses = computed(() => ({
'theme-default': state.useDefaultTheme
// "holiday-us-traditional": state.useHolidayTheme,
// "holiday-us-official": state.useHolidayTheme,
}))
// 날짜 클래스를 계산하는 메서드 정의
const myDateClasses = (): Record<string, string[]> => {
// This was added to demonstrate the dateClasses prop. Note in particular that the
// keys of the object are `yyyy-mm-dd` ISO date strings (not dates), and the values
// for those keys are strings or string arrays. Keep in mind that your CSS to style these
// may need to be fairly specific to make it override your theme's styles. See the
// CSS at the bottom of this component to see how these are styled.
const o = {} as Record<string, string[]>
const theFirst = thisMonth(1)
const ides = [2, 4, 6, 9].includes(theFirst.getMonth()) ? 15 : 13
const idesDate = thisMonth(ides)
o[CalendarMath.isoYearMonthDay(idesDate)] = ['ides']
o[CalendarMath.isoYearMonthDay(thisMonth(21))] = ['do-you-remember', 'the-21st']
return o
}
// 마운트 후 수행할 작업 정의
onMounted((): void => {
state.newItemStartDate = CalendarMath.isoYearMonthDay(CalendarMath.today())
state.newItemEndDate = CalendarMath.isoYearMonthDay(CalendarMath.today())
})
... 생략
해결 방법
달력 컴포넌트안의 props 값이 뜨지 않는 이유는,
props 값을 달력 컴포넌트가 전달받기도 전에 데이터바인딩을 시도하기 때문이다.
props 값을 달력 컴포넌트가 제대로 전달 받아서 바인딩을 시키려면 어떻게 해야할까?
1. ref 로 변수 선언
const date = ref('') // 추가 🎯
const type = ref('') // 추가 🎯
2. 데이터 바인딩 시 필요한 변수 state 값을 원래 부분에서 지우고,
const state = reactive({
showDate: thisMonth(1), // 캘린더에 표시할 현재 달의 첫 날짜
message: '', // 상태 메시지
startingDayOfWeek: 0, // 주의 시작 요일 (0: Sunday, 1: Monday, ..., 6: Saturday)
disablePast: false, // 과거 날짜 사용 금지 여부
disableFuture: false, // 미래 날짜 사용 금지 여부
displayPeriodUom: 'month', // 표시 기간의 단위 (예: 'month', 'year')
displayPeriodCount: 1, // 표시할 기간의 개수
displayWeekNumbers: false, // 주 번호 표시 여부
// showTimes: true, // 시간 표시 여부
selectionStart: undefined, // 선택 시작 날짜
selectionEnd: undefined, // 선택 종료 날짜
newItemTitle: '', // 새로운 아이템 제목
newItemStartDate: '', // 새로운 아이템 시작 날짜
newItemEndDate: '', // 새로운 아이템 종료 날짜
useDefaultTheme: true, // 기본 테마 사용 여부
// useHolidayTheme: true, // 휴일 테마 사용 여부
useTodayIcons: true, // 오늘 아이콘 사용 여부
// items: [ // 여기 지우고 🎯
// {
// startDate: thisMonth(Number(date.value)), // 아이템 시작 날짜 설정
// // title: props.reserveType, // 아이템 제목 설정
// title: date.value,
// url: 'https://en.wikipedia.org/wiki/Birthday' // 아이템 URL 설정
// }
// // {
// // id: "e11",
// // startDate: thisMonth(29),
// // title: "수술",
// // },
// ] as ICalendarItem[] // 캘린더에 표시할 아이템 배열
} as IExampleState)
3. watch 함수 추가해서 props가 변경이 될 때마다 다시 바인딩을 시도했다.
// 이거 추가 🎯
watch(props, () => {
date.value = props.reserveDate
type.value = props.reserveType
state.items = [
{
id: 'e1',
startDate: thisMonth(Number(date.value)), // 아이템 시작 날짜 설정
// title: props.reserveType, // 아이템 제목 설정
title: type.value,
url: 'https://en.wikipedia.org/wiki/Birthday' // 아이템 URL 설정
}
]
console.log('state============?????????????', state)
})
참고로,
state.items를 추가해주면 바인딩이 되는 이유는
아래처럼 달력컴포넌트 안에 또 <CalendarView>라는 컴포넌트가 있고,
거기서 items 를 props로 전달해주기 때문에 가능한거겠지!
<template>
<div id="example-full">
<div class="calendar-parent">
<CalendarView
:items="state.items"
:show-date="state.showDate"
:time-format-options="{ hour: 'numeric', minute: '2-digit' }"
:enable-drag-drop="true"
:disable-past="state.disablePast"
:disable-future="state.disableFuture"
:show-times="state.showTimes"
:date-classes="myDateClasses()"
:display-period-uom="state.displayPeriodUom"
:display-period-count="state.displayPeriodCount"
:starting-day-of-week="state.startingDayOfWeek"
:class="themeClasses"
:period-changed-callback="periodChanged"
:current-period-label="state.useTodayIcons ? 'icons' : ''"
:displayWeekNumbers="state.displayWeekNumbers"
:enable-date-selection="true"
:selection-start="state.selectionStart"
:selection-end="state.selectionEnd"
@date-selection-start="setSelection"
@date-selection="setSelection"
@date-selection-finish="finishSelection"
@drop-on-date="onDrop"
@click-date="onClickDay"
@click-item="onClickItem"
>
<!-- 달력 헤더 -->
<template #header="{ headerProps }">
<CalendarViewHeader :header-props="headerProps" @input="setShowDate" />
</template>
<template> </template>
</CalendarView>
</div>
</div>
</template>
이렇게 하면,
콘솔창에 이렇게 아주 잘 찍히고
원했던 달력에 데이터 바인딩도 잘 된다!
해결된 전체 코드
list뷰 코드는 수정되지 않았고, 달력 컴포넌트 뷰 코드만 수정되었다.
<script setup lang="ts">
// Using the publish version, you would do this instead:
// import { CalendarView, CalendarViewHeader, CalendarMath } from "vue-simple-calendar"
import CalendarView from '../vue-simple-calendar/CalendarView.vue'
import CalendarViewHeader from '../vue-simple-calendar/CalendarViewHeader.vue'
import CalendarMath from '../vue-simple-calendar/CalendarMath'
import { ICalendarItem, INormalizedCalendarItem } from './ICalendarItem'
import { onMounted, reactive, defineEmits } from 'vue'
/**
|--------------------------------------------------
| 😃 1. 변수
|--------------------------------------------------
*/
const date = ref('') // 추가 🎯
const type = ref('') // 추가 🎯
// 현재 달을 가져오는 함수 (선택적으로 시간 및 분도 포함)
const thisMonth = (d: number, h?: number, m?: number): Date => {
const t = new Date()
return new Date(t.getFullYear(), t.getMonth(), d, h || 0, m || 0)
}
// 부모 컴포넌트로부터 받은 props 정의
const props = defineProps<{ reserveDate: string; reserveType: string; data: any }>() // 부모Component에서 받은값
console.log('props!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ', props)
console.log('props.reserveDate!!!!!!!!!!!!!!!', date.value)
console.log('props.reserveType!!!!!!!!!!!!!!! ', props.reserveType)
console.log('props.data~~~~~~~~~~~~~~ ~~~~~~ ~~~~ ~~~~~~~~~ ~~~~~ ', props.data)
// 상태 객체를 반응적으로 정의
interface IExampleState {
showDate: Date // 캘린더에 표시되는 날짜
message: string // 상태 메시지
startingDayOfWeek: number // 주의 시작 요일 (0: Sunday, 1: Monday, ..., 6: Saturday)
disablePast: boolean // 과거 날짜 사용 금지 여부
disableFuture: boolean // 미래 날짜 사용 금지 여부
displayPeriodUom: string // 표시 기간 단위 (예: 'month', 'year')
displayPeriodCount: number // 표시 기간 개수
displayWeekNumbers: boolean // 주 번호 표시 여부
showTimes: boolean // 시간 표시 여부
selectionStart?: Date // 선택 시작 날짜
selectionEnd?: Date // 선택 종료 날짜
newItemTitle: string // 새로운 아이템 제목
newItemStartDate: string // 새로운 아이템 시작 날짜
newItemEndDate: string // 새로운 아이템 종료 날짜
useDefaultTheme: boolean // 기본 테마 사용 여부
useHolidayTheme: boolean // 휴일 테마 사용 여부
useTodayIcons: boolean // 오늘 아이콘 사용 여부
items: ICalendarItem[] // 캘린더에 표시되는 아이템 배열
}
const state = reactive({
showDate: thisMonth(1), // 캘린더에 표시할 현재 달의 첫 날짜
message: '', // 상태 메시지
startingDayOfWeek: 0, // 주의 시작 요일 (0: Sunday, 1: Monday, ..., 6: Saturday)
disablePast: false, // 과거 날짜 사용 금지 여부
disableFuture: false, // 미래 날짜 사용 금지 여부
displayPeriodUom: 'month', // 표시 기간의 단위 (예: 'month', 'year')
displayPeriodCount: 1, // 표시할 기간의 개수
displayWeekNumbers: false, // 주 번호 표시 여부
// showTimes: true, // 시간 표시 여부
selectionStart: undefined, // 선택 시작 날짜
selectionEnd: undefined, // 선택 종료 날짜
newItemTitle: '', // 새로운 아이템 제목
newItemStartDate: '', // 새로운 아이템 시작 날짜
newItemEndDate: '', // 새로운 아이템 종료 날짜
useDefaultTheme: true, // 기본 테마 사용 여부
// useHolidayTheme: true, // 휴일 테마 사용 여부
useTodayIcons: true, // 오늘 아이콘 사용 여부
// items: [ // 여기 지우고 🎯
// {
// startDate: thisMonth(Number(date.value)), // 아이템 시작 날짜 설정
// // title: props.reserveType, // 아이템 제목 설정
// title: date.value,
// url: 'https://en.wikipedia.org/wiki/Birthday' // 아이템 URL 설정
// }
// // {
// // id: "e11",
// // startDate: thisMonth(29),
// // title: "수술",
// // },
// ] as ICalendarItem[] // 캘린더에 표시할 아이템 배열
} as IExampleState)
// const userLocale = computed((): string => CalendarMath.getDefaultBrowserLocale())
// const dayNames = computed((): string[] => CalendarMath.getFormattedWeekdayNames(userLocale.value, "long", 0))
// 계산된 속성 정의
const themeClasses = computed(() => ({
'theme-default': state.useDefaultTheme
// "holiday-us-traditional": state.useHolidayTheme,
// "holiday-us-official": state.useHolidayTheme,
}))
// 날짜 클래스를 계산하는 메서드 정의
const myDateClasses = (): Record<string, string[]> => {
// This was added to demonstrate the dateClasses prop. Note in particular that the
// keys of the object are `yyyy-mm-dd` ISO date strings (not dates), and the values
// for those keys are strings or string arrays. Keep in mind that your CSS to style these
// may need to be fairly specific to make it override your theme's styles. See the
// CSS at the bottom of this component to see how these are styled.
const o = {} as Record<string, string[]>
const theFirst = thisMonth(1)
const ides = [2, 4, 6, 9].includes(theFirst.getMonth()) ? 15 : 13
const idesDate = thisMonth(ides)
o[CalendarMath.isoYearMonthDay(idesDate)] = ['ides']
o[CalendarMath.isoYearMonthDay(thisMonth(21))] = ['do-you-remember', 'the-21st']
return o
}
// 마운트 후 수행할 작업 정의
onMounted((): void => {
state.newItemStartDate = CalendarMath.isoYearMonthDay(CalendarMath.today())
state.newItemEndDate = CalendarMath.isoYearMonthDay(CalendarMath.today())
})
// 이거 추가 🎯
watch(props, () => {
date.value = props.reserveDate
type.value = props.reserveType
state.items = [
{
id: 'e1',
startDate: thisMonth(Number(date.value)), // 아이템 시작 날짜 설정
// title: props.reserveType, // 아이템 제목 설정
title: type.value,
url: 'https://en.wikipedia.org/wiki/Birthday' // 아이템 URL 설정
}
]
console.log('state===================///////////////////////////////////??????????????', state)
})
/**
|--------------------------------------------------
| 🔑 2. 일반 함수
|--------------------------------------------------
*/
// 기간 변경을 처리하는 함수
const periodChanged = (): void => {
// 이 정보를 사용하여 아무 작업도 수행하지 않습니다.
// 단순히 표시 범위의 변경을 수신하고 이에 반응하는 방법을 보여주기 위해 메서드를 포함합니다.
//console.log(eventSource)
//console.log(range)
}
// 부모 컴포넌트에 메시지를 전달하기 위한 이벤트 정의
const emit = defineEmits(['toggle-drawer'])
// 날짜 클릭을 처리하는 함수
const onClickDay = (d: Date): void => {
state.selectionStart = undefined
state.selectionEnd = undefined
state.message = `You clicked: ${d.toLocaleDateString()}`
let dateString = d.toString().slice(8, 10) // 26
console.log('dateString~~~~~~ ~~~~ ~~~~~ ~~~ ~ ~~ ~~ ~ ~ ', dateString)
if (props.reserveDate === dateString) {
emit('toggle-drawer')
}
}
// 항목 클릭을 처리하는 함수
const onClickItem = (item: INormalizedCalendarItem): void => {
state.message = `You clicked: ${item.title}`
console.log('item~~~~~~~~~~~~~~~~~~~~~~~~~ ', item)
}
// 표시할 날짜 설정을 처리하는 함수
const setShowDate = (d: Date): void => {
state.message = `Changing calendar view to ${d.toLocaleDateString()}`
state.showDate = d
}
// 선택 설정을 처리하는 함수
const setSelection = (dateRange: Date[]): void => {
state.selectionEnd = dateRange[1]
state.selectionStart = dateRange[0]
}
// 선택 완료를 처리하는 함수
const finishSelection = (dateRange: Date[]): void => {
setSelection(dateRange)
state.message = `You selected: ${state.selectionStart?.toLocaleDateString() ?? 'n/a'} - ${
state.selectionEnd?.toLocaleDateString() ?? 'n/a'
}`
}
// 드롭 이벤트를 처리하는 함수
const onDrop = (item: INormalizedCalendarItem, date: Date): void => {
state.message = `You dropped ${item.id} on ${date.toLocaleDateString()}`
// 이전 시작 날짜와 선택한 날짜 사이의 차이를 결정하고,
// 해당 차이를 시작 및 종료 날짜에 모두 적용하여 항목을 이동합니다.
const eLength = CalendarMath.dayDiff(item.startDate, date)
item.originalItem.startDate = CalendarMath.addDays(item.startDate, eLength)
item.originalItem.endDate = CalendarMath.addDays(item.endDate, eLength)
}
// 항목 추가를 처리하는 함수
// const clickTestAddItem = (): void => {
// state.items.push({
// startDate: CalendarMath.fromIsoStringToLocalDate(state.newItemStartDate),
// endDate: CalendarMath.fromIsoStringToLocalDate(state.newItemEndDate),
// title: state.newItemTitle,
// id: "e" + Math.random().toString(36).substring(2, 11),
// })
// state.message = "You added a calendar item!"
// }
</script>
<!-- /**
|--------------------------------------------------
| 🎨 화면
|--------------------------------------------------
*/ -->
<template>
<div id="example-full">
<div class="calendar-parent">
<CalendarView
:items="state.items"
:show-date="state.showDate"
:time-format-options="{ hour: 'numeric', minute: '2-digit' }"
:enable-drag-drop="true"
:disable-past="state.disablePast"
:disable-future="state.disableFuture"
:show-times="state.showTimes"
:date-classes="myDateClasses()"
:display-period-uom="state.displayPeriodUom"
:display-period-count="state.displayPeriodCount"
:starting-day-of-week="state.startingDayOfWeek"
:class="themeClasses"
:period-changed-callback="periodChanged"
:current-period-label="state.useTodayIcons ? 'icons' : ''"
:displayWeekNumbers="state.displayWeekNumbers"
:enable-date-selection="true"
:selection-start="state.selectionStart"
:selection-end="state.selectionEnd"
@date-selection-start="setSelection"
@date-selection="setSelection"
@date-selection-finish="finishSelection"
@drop-on-date="onDrop"
@click-date="onClickDay"
@click-item="onClickItem"
>
<!-- 달력 헤더 잠깐 주석 .. -->
<template #header="{ headerProps }">
<CalendarViewHeader :header-props="headerProps" @input="setShowDate" />
</template>
<template> </template>
</CalendarView>
</div>
</div>
</template>
<style>
@import 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.min.css';
/* npm 패키지를 사용하는 앱의 경우 아래 URL은 /node_modules/vue-simple-calendar/dist/css/를 참조해야 합니다 */
@import '/css/gcal.css';
@import '/css/holidays-us.css';
@import '/css/holidays-ue.css';
/* 전체 예제 컨테이너 스타일 */
#example-full {
display: flex;
flex-direction: row;
font-family: Calibri, sans-serif;
width: 86vw; /* 전체 너비는 화면 너비의 86%로 설정 */
min-width: 30rem; /* 최소 너비는 30rem으로 설정 */
max-width: 90rem; /* 최대 너비는 90rem으로 설정 */
min-height: 55rem; /* 최소 높이는 55rem으로 설정 */
margin-left: auto; /* 왼쪽 여백을 자동으로 설정하여 가운데 정렬 */
margin-right: auto; /* 오른쪽 여백을 자동으로 설정하여 가운데 정렬 */
}
/* #example-full .calendar-controls {
margin-right: 1rem;
min-width: 14rem;
max-width: 14rem;
} */
/* 달력 부모 컨테이너 스타일 */
#example-full .calendar-parent {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow-x: hidden;
overflow-y: hidden;
max-height: 90vh; /* 최대 높이는 화면 높이의 90%로 설정 */
background-color: white; /* 배경색은 흰색으로 설정 */
}
/* 달력의 각 주의 높이를 조정하는 스타일 */
#example-full .cv-wrapper.period-month.periodCount-2 .cv-week,
#example-full .cv-wrapper.period-month.periodCount-3 .cv-week,
#example-full .cv-wrapper.period-year .cv-week {
min-height: 7rem; /* 주당 최소 높이는 7rem으로 설정 */
}
/* 특정 날짜에 배경색을 변경하는 예제 - 분홍색 */
/* #example-full .theme-default .cv-day.ides {
background-color: #ffe0e0;
} */
/* 날짜 요소에 아이콘을 추가하는 예제 */
/* #example-full .ides .cv-day-number::before {
content: "\271D"; // 특별한 아이콘
}
#example-full .cv-day.do-you-remember.the-21st .cv-day-number::after {
content: "\1F30D\1F32C\1F525"; // 다른 특별한 아이콘들
} */
</style>