From d1070e010c72ea1c645674d97032b65e09924710 Mon Sep 17 00:00:00 2001 From: inottn Date: Sat, 20 Jul 2024 21:46:14 +0800 Subject: [PATCH] fix(Calendar): correctly change the panelDate when the selected date is the last day of month (#13008) --- packages/vant/src/calendar/CalendarHeader.tsx | 40 +++++++++++-------- .../src/calendar/test/switch-mode.spec.ts | 33 +++++++++++++++ packages/vant/src/calendar/utils.ts | 10 +++++ 3 files changed, 67 insertions(+), 16 deletions(-) diff --git a/packages/vant/src/calendar/CalendarHeader.tsx b/packages/vant/src/calendar/CalendarHeader.tsx index 6adae946f..2f707357e 100644 --- a/packages/vant/src/calendar/CalendarHeader.tsx +++ b/packages/vant/src/calendar/CalendarHeader.tsx @@ -38,25 +38,33 @@ export default defineComponent({ emits: ['clickSubtitle', 'panelChange'], setup(props, { slots, emit }) { - const prevMonthDisabled = computed(() => { - const prevMonth = getPrevMonth(props.date!); - return props.minDate && compareMonth(prevMonth, props.minDate) < 0; - }); + const prevMonthDisabled = computed( + () => + props.date && + props.minDate && + compareMonth(getPrevMonth(props.date), props.minDate) < 0, + ); - const prevYearDisabled = computed(() => { - const prevYear = getPrevYear(props.date!); - return props.minDate && compareMonth(prevYear, props.minDate) < 0; - }); + const prevYearDisabled = computed( + () => + props.date && + props.minDate && + compareMonth(getPrevYear(props.date), props.minDate) < 0, + ); - const nextMonthDisabled = computed(() => { - const nextMonth = getNextMonth(props.date!); - return props.maxDate && compareMonth(nextMonth, props.maxDate) > 0; - }); + const nextMonthDisabled = computed( + () => + props.date && + props.maxDate && + compareMonth(getNextMonth(props.date), props.maxDate) > 0, + ); - const nextYearDisabled = computed(() => { - const nextYear = getNextYear(props.date!); - return props.maxDate && compareMonth(nextYear, props.maxDate) > 0; - }); + const nextYearDisabled = computed( + () => + props.date && + props.maxDate && + compareMonth(getNextYear(props.date), props.maxDate) > 0, + ); const renderTitle = () => { if (props.showTitle) { diff --git a/packages/vant/src/calendar/test/switch-mode.spec.ts b/packages/vant/src/calendar/test/switch-mode.spec.ts index 8241e1b30..815bf16b3 100644 --- a/packages/vant/src/calendar/test/switch-mode.spec.ts +++ b/packages/vant/src/calendar/test/switch-mode.spec.ts @@ -226,3 +226,36 @@ test('should emit panelChange event', async () => { currentDate = getNextMonth(currentDate); expect(onPanelChange).toHaveBeenLastCalledWith({ date: currentDate }); }); + +test('correctly change the panelDate when the selected date is the last day of each month', async () => { + let defaultDate = new Date(2024, 4, 31); + const onPanelChange = vi.fn(); + const wrapper = mount(Calendar, { + props: { + defaultDate, + poppable: false, + switchMode: 'month', + onPanelChange, + }, + }); + + await later(); + const nextMonth = wrapper.findAll('.van-calendar__header-action')[1]; + + await nextMonth.trigger('click'); + let panelDate = getNextMonth(defaultDate); + expect(panelDate).toEqual(new Date(2024, 5, 30)); + expect(onPanelChange).toHaveBeenLastCalledWith({ date: panelDate }); + + defaultDate = new Date(2024, 1, 29); + await wrapper.setProps({ + defaultDate, + switchMode: 'year-month', + }); + const nextYear = wrapper.findAll('.van-calendar__header-action')[3]; + + await nextYear.trigger('click'); + panelDate = getNextYear(defaultDate); + expect(panelDate).toEqual(new Date(2025, 1, 28)); + expect(onPanelChange).toHaveBeenLastCalledWith({ date: panelDate }); +}); diff --git a/packages/vant/src/calendar/utils.ts b/packages/vant/src/calendar/utils.ts index 0da05f7c2..962b720df 100644 --- a/packages/vant/src/calendar/utils.ts +++ b/packages/vant/src/calendar/utils.ts @@ -46,12 +46,22 @@ export function getDayByOffset(date: Date, offset: number) { export function getMonthByOffset(date: Date, offset: number) { const cloned = cloneDate(date); cloned.setMonth(cloned.getMonth() + offset); + + if (cloned.getDate() !== date.getDate()) { + cloned.setDate(0); + } + return cloned; } export function getYearByOffset(date: Date, offset: number) { const cloned = cloneDate(date); cloned.setFullYear(cloned.getFullYear() + offset); + + if (cloned.getDate() !== date.getDate()) { + cloned.setDate(0); + } + return cloned; }