diff --git a/src/packages/calendar/__tests__/__snapshots__/calendar.spec.tsx.snap b/src/packages/calendar/__tests__/__snapshots__/calendar.spec.tsx.snap index 8038085148..246fb5790c 100644 --- a/src/packages/calendar/__tests__/__snapshots__/calendar.spec.tsx.snap +++ b/src/packages/calendar/__tests__/__snapshots__/calendar.spec.tsx.snap @@ -1,3 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`should render slot correctly 1`] = `"
2022年02月
custom30
下旬
custom31
下旬
custom1
上旬
custom2
上旬
custom3
上旬
custom4
上旬
custom5
上旬
custom6
上旬
custom7
上旬
custom8
上旬
custom9
上旬
custom10
上旬
custom11
下旬
custom12
下旬
custom13
下旬
custom14
下旬
custom15
下旬
custom16
下旬
custom17
下旬
custom18
下旬
custom19
下旬
custom20
下旬
custom21
下旬
custom22
下旬
custom23
下旬
custom24
下旬
custom25
下旬
custom26
下旬
custom27
下旬
custom28
下旬
2022年03月
custom27
下旬
custom28
下旬
custom1
上旬
custom2
上旬
custom3
上旬
custom4
上旬
custom5
上旬
custom6
上旬
custom7
上旬
custom8
上旬
custom9
上旬
custom10
上旬
custom11
下旬
custom12
下旬
custom13
下旬
custom14
下旬
custom15
下旬
custom16
下旬
custom17
下旬
custom18
下旬
custom19
下旬
custom20
下旬
custom21
下旬
custom22
下旬
custom23
下旬
custom24
下旬
custom25
下旬
custom26
下旬
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
custom31
下旬
2022年04月
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
custom31
下旬
custom1
上旬
custom2
上旬
custom3
上旬
custom4
上旬
custom5
上旬
custom6
上旬
custom7
上旬
custom8
上旬
custom9
上旬
custom10
上旬
custom11
下旬
custom12
下旬
custom13
下旬
custom14
下旬
custom15
下旬
custom16
下旬
custom17
下旬
custom18
下旬
custom19
下旬
custom20
下旬
custom21
下旬
custom22
下旬
custom23
下旬
custom24
下旬
custom25
下旬
custom26
下旬
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
2022年05月
custom1
上旬
custom2
上旬
custom3
上旬
custom4
上旬
custom5
上旬
custom6
上旬
custom7
上旬
custom8
上旬
custom9
上旬
custom10
上旬
custom11
下旬
custom12
下旬
custom13
下旬
custom14
下旬
custom15
下旬
custom16
下旬
custom17
下旬
custom18
下旬
custom19
下旬
custom20
下旬
custom21
下旬
custom22
下旬
custom23
下旬
custom24
下旬
custom25
下旬
custom26
下旬
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
custom31
下旬
"`; +exports[`range prop 1`] = `"
2025年01月
30
31
1
开始
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2025年02月
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
今天
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2025年03月
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
结束
"`; + +exports[`should render slot correctly 1`] = `"
2022年03月
custom27
下旬
custom28
下旬
custom1
上旬
custom2
上旬
custom3
上旬
custom4
上旬
custom5
上旬
custom6
上旬
custom7
上旬
custom8
上旬
custom9
上旬
custom10
复盘
上旬
custom11
下旬
custom12
下旬
custom13
下旬
custom14
下旬
custom15
下旬
custom16
下旬
custom17
下旬
custom18
下旬
custom19
下旬
custom20
下旬
custom21
下旬
custom22
下旬
custom23
下旬
custom24
下旬
custom25
下旬
custom26
下旬
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
custom31
下旬
2022年04月
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
custom31
下旬
custom1
上旬
custom2
上旬
custom3
上旬
custom4
上旬
custom5
上旬
custom6
上旬
custom7
上旬
custom8
上旬
custom9
上旬
custom10
复盘
上旬
custom11
下旬
custom12
下旬
custom13
下旬
custom14
下旬
custom15
下旬
custom16
下旬
custom17
下旬
custom18
下旬
custom19
下旬
custom20
下旬
custom21
下旬
custom22
下旬
custom23
下旬
custom24
下旬
custom25
下旬
custom26
下旬
custom27
下旬
custom28
下旬
custom29
下旬
custom30
下旬
"`; + +exports[`week prop 1`] = `"
2025年01月
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2025年02月
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
开始
11
12
13
今天
14
15
16
结束
17
18
19
20
21
22
23
24
25
26
27
28
2025年03月
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"`; diff --git a/src/packages/calendar/__tests__/calendar.spec.tsx b/src/packages/calendar/__tests__/calendar.spec.tsx index a21f11c3c4..c36848db2f 100644 --- a/src/packages/calendar/__tests__/calendar.spec.tsx +++ b/src/packages/calendar/__tests__/calendar.spec.tsx @@ -1,114 +1,123 @@ import * as React from 'react' import { render, fireEvent } from '@testing-library/react' import '@testing-library/jest-dom' -import { CalendarDay } from '@/packages/calendar/types' - +import { CalendarDay, CalendarType } from '@/packages/calendar/types' import { Calendar } from '../calendar' -test('show-title prop', async () => { +test('single prop', async () => { + const onConfirm = vi.fn() const { container, rerender } = render( ) - const canlendarTitle1 = container.querySelectorAll( '.nut-calendar-header .nut-calendar-title' ) - expect(canlendarTitle1.length).toBe(1) + const curMonth1 = container.querySelectorAll('.nut-calendar-sub-title') + expect(curMonth1.length).toBe(1) + const calendarConfirmBtn = container.querySelectorAll( + '.calendar-confirm-btn' + )[0] + fireEvent.click(calendarConfirmBtn) + expect(onConfirm).toBeCalled() rerender( ) - const canlendarTitle2 = container.querySelectorAll( '.nut-calendar-header .nut-calendar-title' ) - expect(canlendarTitle2.length).toBe(0) + const curMonth2 = container.querySelectorAll('.nut-calendar-sub-title') + expect(curMonth2.length).toBe(0) + const tipCurr = container.querySelectorAll('.nut-calendar-day-info-curr') + expect(tipCurr.length).toBe(0) }) -test('show-sub-title prop', async () => { - const { container, rerender } = render( +test('week prop', async () => { + const { container } = render( ) + const viewArea = container.querySelector('.viewArea') as HTMLElement + expect(viewArea.innerHTML).toMatchSnapshot() +}) - const curMonth1 = container.querySelectorAll('.nut-calendar-sub-title') - - expect(curMonth1.length).toBe(1) - - rerender( +test('range prop', async () => { + const { container } = render( ) - - const curMonth2 = container.querySelectorAll('.nut-calendar-sub-title') - - expect(curMonth2.length).toBe(0) + const viewArea = container.querySelector('.viewArea') as HTMLElement + expect(viewArea.innerHTML).toMatchSnapshot() }) -test('show-today prop', async () => { +test('popup prop', async () => { const { container } = render( ) - - const tipCurr = container.querySelectorAll('.nut-calendar-day-info-curr') - - expect(tipCurr.length).toBe(0) + const popupNode = container.querySelectorAll('.nut-popup') + expect(popupNode.length).toBe(0) }) test('should render slot correctly', async () => { - const renderHeaderButtons = () => { - return
最近七天
- } - - const renderDay = (date: CalendarDay) => { - return custom{date.day} - } - - const renderDayBottom = (date: CalendarDay) => { - return {Number(date.day) <= 10 ? '上旬' : '下旬'} - } - + const renderHeaderButtons = () =>
最近七天
+ const renderDay = (date: CalendarDay) => custom{date.day} + const renderDayTop = (date: CalendarDay) => ( + {Number(date.day) === 10 ? '复盘' : ''} + ) + const renderDayBottom = (date: CalendarDay) => ( + {Number(date.day) <= 10 ? '上旬' : '下旬'} + ) const { container } = render( ) - const topSlot = container.querySelector( '.nut-calendar-header-buttons' ) as HTMLElement @@ -117,40 +126,104 @@ test('should render slot correctly', async () => { expect(viewArea.innerHTML).toMatchSnapshot() }) +const testClickEvent = ( + type: CalendarType, + startDate: string, + endDate: string, + offset: number, + expected: string, + defaultValue: string | string[] = '2025-01-03' +) => { + const onDayClick = vi.fn() + const { container } = render( + + ) + const calendarMonthDay = + container.querySelectorAll('.nut-calendar-day')[offset] + fireEvent.click(calendarMonthDay) + expect(onDayClick).toBeCalled() + const start = container.querySelectorAll( + '.nut-calendar-day-active .nut-calendar-day-day' + )[0] + expect(start.innerHTML).toBe(expected) +} + test('select event when click item', () => { + testClickEvent('single', '2025-01-01', '2025-12-31', 3, '1') +}) + +test('week select event when click item', () => { + testClickEvent('week', '2025-01-01', '2025-01-31', 15, '12', ['2025-01-04']) + testClickEvent('week', '2025-01-01', '2025-01-31', 4, '1', ['2025-01-27']) + testClickEvent('week', '2025-01-01', '2025-01-31', 30, '26') +}) + +test('multiple select event when click item', () => { const onDayClick = vi.fn() const { container } = render( ) - const calendarMonthDay = container.querySelectorAll('.nut-calendar-day')[15] + const start1 = container.querySelectorAll( + '.nut-calendar-day-active .nut-calendar-day-day' + )[0] + expect(start1.innerHTML).toBe('1') + const calendarMonthDay = container.querySelectorAll('.nut-calendar-day')[15] fireEvent.click(calendarMonthDay) expect(onDayClick).toBeCalled() + const start2 = container.querySelectorAll( + '.nut-calendar-day-active .nut-calendar-day-day' + )[1] + expect(start2.innerHTML).toBe('13') + + const calendarMonthDay2 = container.querySelectorAll('.nut-calendar-day')[16] + fireEvent.click(calendarMonthDay2) + expect(onDayClick).toBeCalled() + const start3 = container.querySelectorAll( + '.nut-calendar-day-active .nut-calendar-day-day' + )[2] + expect(start3.innerHTML).toBe('14') }) -test('choose event when click item', async () => { - const onConfirm = vi.fn() +test('range select event when click item', () => { + const onDayClick = vi.fn() const { container } = render( ) - - const calendarConfirmBtn = container.querySelectorAll( - '.calendar-confirm-btn' + const calendarMonthDay = container.querySelectorAll('.nut-calendar-day')[15] + fireEvent.click(calendarMonthDay) + expect(onDayClick).toBeCalled() + const start = container.querySelectorAll( + '.nut-calendar-day-active .nut-calendar-day-day' )[0] + expect(start.innerHTML).toBe('13') - fireEvent.click(calendarConfirmBtn) - expect(onConfirm).toBeCalled() + const calendarMonthDay2 = container.querySelectorAll('.nut-calendar-day')[20] + fireEvent.click(calendarMonthDay2) + expect(onDayClick).toBeCalled() + const next = container.querySelectorAll( + '.nut-calendar-day-choose .nut-calendar-day-day' + )[0] + expect(next.innerHTML).toBe('14') }) diff --git a/src/packages/calendar/calendar.scss b/src/packages/calendar/calendar.scss index 12ea18cd4e..4a9d9267c8 100644 --- a/src/packages/calendar/calendar.scss +++ b/src/packages/calendar/calendar.scss @@ -190,18 +190,18 @@ } } - &-choose-disabled { - background-color: $calendar-choose-disable-background-color; - color: $calendar-disable-color !important; - - .nut-calendar-day-info-curr { - display: none; - } - } - &-choose { background-color: $calendar-choose-background-color; color: $calendar-choose-color; + + &-disabled { + background-color: $calendar-choose-disable-background-color; + color: $calendar-disable-color !important; + + .nut-calendar-day-info-curr { + display: none; + } + } } } diff --git a/src/packages/calendar/calendar.taro.tsx b/src/packages/calendar/calendar.taro.tsx index 713eabee14..e1fc7057c7 100644 --- a/src/packages/calendar/calendar.taro.tsx +++ b/src/packages/calendar/calendar.taro.tsx @@ -1,7 +1,7 @@ import React, { useRef, ReactNode } from 'react' import Popup from '@/packages/popup/index.taro' import CalendarItem from '@/packages/calendaritem/index.taro' -import { Utils } from '@/utils/date' +import { getDateString } from '@/utils/date' import { useConfig } from '@/packages/configprovider/configprovider.taro' import type { CalendarDay, CalendarType, CalendarRef } from './types' import { ComponentDefaults } from '@/utils/typings' @@ -44,8 +44,8 @@ const defaultProps = { visible: false, title: '', defaultValue: '', - startDate: Utils.getDay(0), - endDate: Utils.getDay(365), + startDate: getDateString(0), + endDate: getDateString(365), showToday: true, startText: '', endText: '', diff --git a/src/packages/calendar/calendar.tsx b/src/packages/calendar/calendar.tsx index 327a1109a5..0c2eba3361 100644 --- a/src/packages/calendar/calendar.tsx +++ b/src/packages/calendar/calendar.tsx @@ -1,7 +1,7 @@ import React, { useRef, ReactNode } from 'react' import Popup from '@/packages/popup' import CalendarItem from '@/packages/calendaritem' -import { Utils } from '@/utils/date' +import { getDateString } from '@/utils/date' import { useConfig } from '@/packages/configprovider' import type { CalendarDay, CalendarType, CalendarRef } from './types' import { ComponentDefaults } from '@/utils/typings' @@ -44,8 +44,8 @@ const defaultProps = { visible: false, title: '', defaultValue: '', - startDate: Utils.getDay(0), - endDate: Utils.getDay(365), + startDate: getDateString(0), + endDate: getDateString(365), showToday: true, startText: '', endText: '', diff --git a/src/packages/calendar/demos/h5/demo10.tsx b/src/packages/calendar/demos/h5/demo10.tsx index a4ac3b3f80..58b19875fb 100644 --- a/src/packages/calendar/demos/h5/demo10.tsx +++ b/src/packages/calendar/demos/h5/demo10.tsx @@ -1,5 +1,6 @@ import React, { useState, useRef } from 'react' import { Cell, Calendar } from '@nutui/nutui-react' +import { date2Str, getDateString } from '@/utils/date' function isLeapYear(y: number): boolean { return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 @@ -28,35 +29,9 @@ function getMonthDays(year: string, month: string): number { )[month as any] } -const padZero = (num: number | string, targetLength = 2) => { - let str = `${num}` - while (str.length < targetLength) { - str = `0${str}` - } - return str -} - -function date2Str(date: Date, split?: string): string { - split = split || '-' - const y = date.getFullYear() - const m = padZero(date.getMonth() + 1) - const d = padZero(date.getDate()) - return [y, m, d].join(split) -} - -function getDay(i: number): string { - i = i || 0 - let date = new Date() - const diff = i * (1000 * 60 * 60 * 24) - date = new Date(date.getTime() + diff) - return date2Str(date) -} - const Demo10 = () => { const [date, setDate] = useState(['2024-07-10', '2024-07-19']) - const [isVisible, setIsVisible] = useState(false) - const calendarRef = useRef(null) const openSwitch = () => { @@ -78,7 +53,7 @@ const Demo10 = () => { } const clickBtn = () => { - const date = [date2Str(new Date()), getDay(6)] + const date = [date2Str(new Date()), getDateString(6)] setDate(date) if (calendarRef.current) { calendarRef.current.scrollToDate(date[0]) diff --git a/src/packages/calendar/demos/h5/demo3.tsx b/src/packages/calendar/demos/h5/demo3.tsx index 9527c74b69..fd5a106ee3 100644 --- a/src/packages/calendar/demos/h5/demo3.tsx +++ b/src/packages/calendar/demos/h5/demo3.tsx @@ -18,6 +18,7 @@ const Demo3 = () => { return item[3] }) setDate([...dateArr]) + console.log('onconfirm', chooseData) } return ( diff --git a/src/packages/calendar/demos/h5/demo4.tsx b/src/packages/calendar/demos/h5/demo4.tsx index 441873e69c..8b97c4e4bf 100644 --- a/src/packages/calendar/demos/h5/demo4.tsx +++ b/src/packages/calendar/demos/h5/demo4.tsx @@ -16,6 +16,7 @@ const Demo4 = () => { const setChooseValue = (chooseData: any) => { const dateArr = [...[chooseData[0][3], chooseData[1][3]]] setDate([...dateArr]) + console.log('choosevalue', chooseData, [...dateArr]) } return ( <> diff --git a/src/packages/calendar/demos/taro/demo1.tsx b/src/packages/calendar/demos/taro/demo1.tsx index 4c94182c12..47604d8a00 100644 --- a/src/packages/calendar/demos/taro/demo1.tsx +++ b/src/packages/calendar/demos/taro/demo1.tsx @@ -1,6 +1,5 @@ import React, { useState } from 'react' import { Cell, Calendar } from '@nutui/nutui-react-taro' -import { Star } from '@nutui/icons-react-taro' const Demo1 = () => { const d = new Date() @@ -35,12 +34,10 @@ const Demo1 = () => { /> } /> ) diff --git a/src/packages/calendar/demos/taro/demo10.tsx b/src/packages/calendar/demos/taro/demo10.tsx index 8cce80afb1..5c4a3be85d 100644 --- a/src/packages/calendar/demos/taro/demo10.tsx +++ b/src/packages/calendar/demos/taro/demo10.tsx @@ -1,5 +1,6 @@ import React, { useState, useRef } from 'react' import { Cell, Calendar } from '@nutui/nutui-react-taro' +import { date2Str, getDateString } from '@/utils/date' function isLeapYear(y: number): boolean { return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 @@ -28,35 +29,9 @@ function getMonthDays(year: string, month: string): number { )[month as any] } -const padZero = (num: number | string, targetLength = 2) => { - let str = `${num}` - while (str.length < targetLength) { - str = `0${str}` - } - return str -} - -function date2Str(date: Date, split?: string): string { - split = split || '-' - const y = date.getFullYear() - const m = padZero(date.getMonth() + 1) - const d = padZero(date.getDate()) - return [y, m, d].join(split) -} - -function getDay(i: number): string { - i = i || 0 - let date = new Date() - const diff = i * (1000 * 60 * 60 * 24) - date = new Date(date.getTime() + diff) - return date2Str(date) -} - const Demo10 = () => { const [date, setDate] = useState(['2024-07-10', '2024-07-19']) - const [isVisible, setIsVisible] = useState(false) - const calendarRef = useRef(null) const openSwitch = () => { @@ -81,7 +56,7 @@ const Demo10 = () => { } const clickBtn = () => { - const date = [date2Str(new Date()), getDay(6)] + const date = [date2Str(new Date()), getDateString(6)] setDate(date) if (calendarRef.current) { calendarRef.current.scrollToDate(date[0]) diff --git a/src/packages/calendar/utils.tsx b/src/packages/calendar/utils.tsx index cf568ff8b8..a4d4bcf4d1 100644 --- a/src/packages/calendar/utils.tsx +++ b/src/packages/calendar/utils.tsx @@ -1,4 +1,4 @@ -import { Utils } from '@/utils/date' +import { isEqual, date2Str, getNumTwoBit } from '@/utils/date' import { CalendarDay, CalendarMonthInfo } from './types' export const splitDate = (date: string) => { @@ -9,7 +9,7 @@ export const splitDate = (date: string) => { export const isMultiple = (day: string, days: string[]) => { if (days.length > 0) { return days.some((item: string) => { - return Utils.isEqual(item, day) + return isEqual(item, day) }) } return false @@ -17,24 +17,22 @@ export const isMultiple = (day: string, days: string[]) => { export const isCurrDay = (month: CalendarMonthInfo, day: string | number) => { const date = `${month.curData[0]}/${month.curData[1]}/${day}` - return Utils.isEqual(date, Utils.date2Str(new Date(), '/')) + return isEqual(date, date2Str(new Date(), '/')) } export const getCurrDate = (day: CalendarDay, month: CalendarMonthInfo) => { - return `${month.curData[0]}/${month.curData[1]}/${Utils.getNumTwoBit( - +day.day - )}` + return `${month.curData[0]}/${month.curData[1]}/${getNumTwoBit(+day.day)}` } export const isStart = (day: string, days: string[]) => { - return Utils.isEqual(days[0], day) + return isEqual(days[0], day) } export const isEnd = (day: string, days: string[]) => { - return Utils.isEqual(days[1], day) + return isEqual(days[1], day) } // 开始结束时间是否相等 export const isStartAndEnd = (days: string[]) => { - return days.length >= 2 && Utils.isEqual(days[0], days[1]) + return days.length >= 2 && isEqual(days[0], days[1]) } diff --git a/src/packages/calendarcard/utils.ts b/src/packages/calendarcard/utils.ts index e329c12c81..2d65a3c3ac 100644 --- a/src/packages/calendarcard/utils.ts +++ b/src/packages/calendarcard/utils.ts @@ -1,4 +1,4 @@ -import { Utils } from '@/utils/date' +import { getMonthPreDay, getMonthDays } from '@/utils/date' import { CalendarCardDay } from './types' export const convertDateToDay = (date: Date) => { @@ -29,13 +29,13 @@ export const getPrevMonthDays = ( prevMonth = 12 prevYear -= 1 } - let days = Utils.getMonthPreDay(year, month) + let days = getMonthPreDay(year, month) days -= firstDayOfWeek if (days >= 7) { days -= 7 } - const preDates = Utils.getMonthDays(`${prevYear}`, `${prevMonth}`) + const preDates = getMonthDays(`${prevYear}`, `${prevMonth}`) const months = Array.from(Array(preDates), (_, k) => { return { type: 'prev', @@ -51,7 +51,7 @@ export const getPrevMonthDays = ( * 获取当前月的日期数据 */ export const getCurrentMonthDays = (year: number, month: number) => { - const days = Utils.getMonthDays(`${year}`, `${month}`) + const days = getMonthDays(`${year}`, `${month}`) return Array.from(Array(days), (_, k) => { return { type: 'current', diff --git a/src/packages/calendaritem/calendaritem.taro.tsx b/src/packages/calendaritem/calendaritem.taro.tsx index 82c847d6d6..49feda0d5a 100644 --- a/src/packages/calendaritem/calendaritem.taro.tsx +++ b/src/packages/calendaritem/calendaritem.taro.tsx @@ -5,10 +5,17 @@ import Taro, { nextTick } from '@tarojs/taro' import { PopupProps } from '@/packages/popup/index.taro' import { ComponentDefaults } from '@/utils/typings' import { - Utils, + getDateString, getCurrMonthData, getDaysStatus, getPreMonthDates, + compareDate, + getMonthDays, + getWeekDate, + formatResultDate, + isEqual, + getNumTwoBit, + getWhatDay, } from '@/utils/date' import requestAniFrame from '@/utils/raf' import { useConfig } from '@/packages/configprovider/configprovider.taro' @@ -71,8 +78,8 @@ const defaultProps = { autoBackfill: false, popup: true, title: '', - startDate: Utils.getDay(0), - endDate: Utils.getDay(365), + startDate: getDateString(0), + endDate: getDateString(365), showToday: true, startText: '', endText: '', @@ -106,6 +113,7 @@ export const CalendarItem = React.forwardRef< type, autoBackfill, title, + value, defaultValue, startDate, endDate, @@ -123,13 +131,15 @@ export const CalendarItem = React.forwardRef< renderDayTop, renderDayBottom, renderBottomButton, - value, onConfirm, onUpdate, onDayClick, onPageChange, } = { ...defaultProps, ...props } + const classPrefix = 'nut-calendar' + const dayPrefix = 'nut-calendar-day' + const weekdays = locale.calendaritem.weekdays const weeks = [ ...weekdays.slice(firstDayOfWeek, 7), @@ -145,8 +155,8 @@ export const CalendarItem = React.forwardRef< const [scrollWithAnimation, setScrollWithAnimation] = useState(false) // 初始化开始结束数据 - const propStartDate = (startDate || Utils.getDay(0)) as string - const propEndDate = (endDate || Utils.getDay(365)) as string + const propStartDate = (startDate || getDateString(0)) as string + const propEndDate = (endDate || getDateString(365)) as string const startDates = splitDate(propStartDate) const endDates = splitDate(propEndDate) @@ -154,14 +164,6 @@ export const CalendarItem = React.forwardRef< currDateArray: [], }) - const getMonthsPanel = () => { - return monthsPanel.current as HTMLDivElement - } - - const getMonthsRef = () => { - return monthsRef.current as HTMLDivElement - } - const resetDefaultValue = () => { if ( defaultValue || @@ -188,11 +190,8 @@ export const CalendarItem = React.forwardRef< const [avgHeight, setAvgHeight] = useState(0) let viewHeight = 0 - const classPrefix = 'nut-calendar' - const dayPrefix = 'nut-calendar-day' - // 获取月数据 - const getMonthData = (curData: string[], monthNum: number, type: string) => { + const getMonthData = (curData: string[], monthNum: number) => { let i = 0 let date = curData const monthData = monthsData @@ -200,57 +199,43 @@ export const CalendarItem = React.forwardRef< const y = parseInt(date[0], 10) const m = parseInt(date[1], 10) const days = [ - ...(getPreMonthDates('prev', y, m, firstDayOfWeek) as CalendarDay[]), - ...(getDaysStatus('active', y, m) as CalendarDay[]), - ] - const cssHeight = 39 + (days.length > 35 ? 384 : 320) - + ...getPreMonthDates('prev', y, m, firstDayOfWeek), + ...getDaysStatus('active', y, m), + ] as CalendarDay[] let scrollTop = 0 if (monthData.length > 0) { const monthEle = monthData[monthData.length - 1] scrollTop = monthEle.scrollTop + monthEle.cssHeight } - const monthInfo: CalendarMonthInfo = { + const cssHeight = 39 + (days.length > 35 ? 384 : 320) + const monthInfo = { curData: date, title: monthTitle(y, m), monthData: days, cssHeight, scrollTop, } - - if (type === 'next') { - if ( - !endDates || - !Utils.compareDate( - `${endDates[0]}/${endDates[1]}/${Utils.getMonthDays( - endDates[0], - endDates[1] - )}`, - `${curData[0]}/${curData[1]}/${curData[2]}` - ) - ) { - monthData.push(monthInfo) - } - } else if ( - !startDates || - !Utils.compareDate( - `${curData[0]}/${curData[1]}/${curData[2]}`, - `${startDates[0]}/${startDates[1]}/01` + if ( + !endDates || + !compareDate( + `${endDates[0]}/${endDates[1]}/${getMonthDays( + endDates[0], + endDates[1] + )}`, + `${curData[0]}/${curData[1]}/${curData[2]}` ) ) { - monthData.unshift(monthInfo) + monthData.push(monthInfo) } - date = getCurrMonthData('next', y, m) as string[] } while (i++ < monthNum) - setMonthsData(monthData) } const setReachedYearMonthInfo = (current: number) => { const currentMonthsData = monthsData[current] - const [year, month] = currentMonthsData.curData if (currentMonthsData.title === yearMonthTitle) return + const [year, month] = currentMonthsData.curData onPageChange && onPageChange([year, month, `${year}-${month}`]) setYearMonthTitle(currentMonthsData.title) } @@ -279,87 +264,72 @@ export const CalendarItem = React.forwardRef< setReachedYearMonthInfo(current) } - const getMonthNum = () => { - let monthNum = Number(endDates[1]) - Number(startDates[1]) - const yearNum = Number(endDates[0]) - Number(startDates[0]) - if (yearNum > 0) { - monthNum += 12 * yearNum - } - if (monthNum <= 0) { - monthNum = 1 - } - setMonthsNum(monthNum) - return monthNum - } const setDefaultDate = () => { let defaultData: CalendarValue = [] - // 日期转化为数组,限制初始日期。判断时间范围 - if (type === 'range' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { - if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { - currentDate.splice(0, 1, propStartDate) - } - if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { - currentDate.splice(1, 1, propEndDate) - } - defaultData = [ - ...splitDate(currentDate[0]), - ...splitDate(currentDate[1]), - ] + if (type === 'single' && typeof currentDate === 'string') { + if (!currentDate.length) { + return defaultData } - } else if (type === 'multiple' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { - const defaultArr = [] as string[] - const obj: Record = {} - currentDate.forEach((item: string) => { - if ( - propStartDate && - !Utils.compareDate(item, propStartDate) && - propEndDate && - !Utils.compareDate(propEndDate, item) - ) { - if (!Object.hasOwnProperty.call(obj, item)) { - defaultArr.push(item) - obj[item] = item - } - } - }) - currentDate.splice(0) && currentDate.push(...defaultArr) - defaultData = [...splitDate(defaultArr[0])] + if (compareDate(currentDate, propStartDate)) { + defaultData = [...splitDate(propStartDate)] + } else if (!compareDate(currentDate, propEndDate)) { + defaultData = [...splitDate(propEndDate)] + } else { + defaultData = [...splitDate(currentDate)] } - } else if (type === 'week' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { - const [y, m, d] = splitDate(currentDate[0]) - const weekArr = Utils.getWeekDate(y, m, d, firstDayOfWeek) - currentDate.splice(0) && currentDate.push(...weekArr) - if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { - currentDate.splice(0, 1, propStartDate) + return defaultData + } + if (Array.isArray(currentDate) && currentDate.length) { + switch (type) { + case 'range': { + if (compareDate(currentDate[0], propStartDate)) { + currentDate[0] = propStartDate + } + if (compareDate(propEndDate, currentDate[1])) { + currentDate[1] = propEndDate + } + defaultData = [ + ...splitDate(currentDate[0]), + ...splitDate(currentDate[1]), + ] + break } - if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { - currentDate.splice(1, 1, propEndDate) + case 'multiple': { + const defaultArr = [] as string[] + const obj: Record = {} + currentDate.forEach((item: string) => { + if ( + !compareDate(item, propStartDate) && + !compareDate(propEndDate, item) + ) { + if (!Object.hasOwnProperty.call(obj, item)) { + defaultArr.push(item) + obj[item] = item + } + } + }) + currentDate.splice(0, currentDate.length, ...defaultArr) + defaultData = [...splitDate(defaultArr[0])] + break } - defaultData = [ - ...splitDate(currentDate[0]), - ...splitDate(currentDate[1]), - ] - } - } else if (currentDate) { - if (currentDate.length > 0) { - if ( - propStartDate && - Utils.compareDate(currentDate as string, propStartDate) - ) { - defaultData = [...splitDate(propStartDate as string)] - } else if ( - propEndDate && - !Utils.compareDate(currentDate as string, propEndDate) - ) { - defaultData = [...splitDate(propEndDate as string)] - } else { - defaultData = [...splitDate(currentDate as string)] + case 'week': { + const [y, m, d] = splitDate(currentDate[0]) + const weekArr = getWeekDate(y, m, d, firstDayOfWeek) + currentDate.splice(0, currentDate.length, ...weekArr) + if (compareDate(currentDate[0], propStartDate)) { + currentDate.splice(0, 1, propStartDate) + } + if (compareDate(propEndDate, currentDate[1])) { + currentDate.splice(1, 1, propEndDate) + } + defaultData = [ + ...splitDate(currentDate[0]), + ...splitDate(currentDate[1]), + ] + break } - } else { - defaultData = [] + default: + break } } return defaultData @@ -385,12 +355,10 @@ export const CalendarItem = React.forwardRef< const date = new Date() const year = date.getFullYear() const month = date.getMonth() + 1 - const index = monthsData.findIndex((item) => { - return +item.curData[0] === year && +item.curData[1] === month - }) - if (index > -1) { - current = index - } + const index = monthsData.findIndex( + (item) => +item.curData[0] === year && +item.curData[1] === month + ) + if (index > -1) current = index } return { current, @@ -398,85 +366,98 @@ export const CalendarItem = React.forwardRef< } } - const renderCurrentDate = () => { - const defaultData: CalendarValue = setDefaultDate() - const current = getCurrentIndex(defaultData) - - if (defaultData.length > 0) { - // 设置当前选中日期 - if (type === 'range') { - chooseDay( - { day: defaultData[2], type: 'active' }, - monthsData[current.current], - true - ) - chooseDay( + const renderCurrentDate = (defaultData: any, current: any) => { + if (!defaultData.length) return + // 设置当前选中日期 + const date = monthsData[current.current] + switch (type) { + case 'range': { + handleDayClick({ day: defaultData[2], type: 'active' }, date) + handleDayClick( { day: defaultData[5], type: 'active' }, - monthsData[current.lastCurrent], - true - ) - } else if (type === 'week') { - chooseDay( - { day: defaultData[2], type: 'curr' }, - monthsData[current.current], - true + monthsData[current.lastCurrent] ) - } else if (type === 'multiple') { + break + } + case 'week': { + handleDayClick({ day: defaultData[2], type: 'curr' }, date) + break + } + case 'multiple': { ;[...currentDate].forEach((item: string) => { const dateArr = splitDate(item) let currentIndex = current.current - monthsData.forEach((item, index) => { - if (item.title === monthTitle(dateArr[0], dateArr[1])) { - currentIndex = index - } - }) - chooseDay( + currentIndex = monthsData.findIndex( + (item) => item.title === monthTitle(dateArr[0], dateArr[1]) + ) + handleDayClick( { day: dateArr[2], type: 'active' }, - monthsData[currentIndex], - true + monthsData[currentIndex] ) }) - } else { - chooseDay( - { day: defaultData[2], type: 'active' }, - monthsData[current.current], - true - ) + break + } + default: { + handleDayClick({ day: defaultData[2], type: 'active' }, date) + break } } - return current.current + } + + const getMonthsPanel = () => { + return monthsPanel.current as HTMLDivElement + } + + const getMonthsRef = () => { + return monthsRef.current as HTMLDivElement } const requestAniFrameFunc = (current: number, monthNum: number) => { const lastItem = monthsData[monthsData.length - 1] const containerHeight = lastItem.cssHeight + lastItem.scrollTop - requestAniFrame(() => { // 初始化 日历位置 if (monthsRef && monthsPanel && viewAreaRef) { viewHeight = getMonthsRef().clientHeight getMonthsPanel().style.height = `${containerHeight}px` - getMonthsRef().scrollTop = monthsData[current].scrollTop - setScrollTop(monthsData[current].scrollTop) + const currTop = monthsData[current].scrollTop + getMonthsRef().scrollTop = currTop + setScrollTop(currTop) nextTick(() => setScrollWithAnimation(true)) } }) setAvgHeight(Math.floor(containerHeight / (monthNum + 1))) } + const getMonthNum = () => { + let monthNum = Number(endDates[1]) - Number(startDates[1]) + const yearNum = Number(endDates[0]) - Number(startDates[0]) + if (yearNum > 0) monthNum += 12 * yearNum + if (monthNum <= 0) monthNum = 1 + setMonthsNum(monthNum) + return monthNum + } + const initData = () => { // 判断时间范围内存在多少个月 const monthNum = getMonthNum() // 设置月份数据,获取包含月份的所有数据,只需要 set 一次即可。 - getMonthData(startDates, monthNum, 'next') - const current = renderCurrentDate() - setDefaultRange(monthNum, current) - requestAniFrameFunc(current, monthNum) + getMonthData(startDates, monthNum) + // 获取当前默认值 + const defaultData = setDefaultDate() + // 获取当前默认值在的月份 + const current = getCurrentIndex(defaultData) + const currentIndex = current.current + // 渲染第一个默认数据 + renderCurrentDate(defaultData, current) + setDefaultRange(monthNum, currentIndex) + requestAniFrameFunc(currentIndex, monthNum) } useEffect(() => { initData() }, []) + const resetRender = () => { state.currDateArray.splice(0) monthsData.splice(0) @@ -492,9 +473,9 @@ export const CalendarItem = React.forwardRef< // 暴露出的API const scrollToDate = (date: string) => { - if (Utils.compareDate(date, propStartDate)) { + if (compareDate(date, propStartDate)) { date = propStartDate - } else if (!Utils.compareDate(date, propEndDate)) { + } else if (!compareDate(date, propEndDate)) { date = propEndDate } const dateArr = splitDate(date) @@ -511,18 +492,17 @@ export const CalendarItem = React.forwardRef< const offset = distance / 10 monthsRef.current.scrollTop += offset } - if (flag >= 10) { clearInterval(interval) if (monthsRef.current) { monthsRef.current.scrollTop = currTop - setScrollTop(monthsRef.current.scrollTop) + setScrollTop(currTop) } } }, 40) } else { monthsRef.current.scrollTop = currTop - setScrollTop(monthsRef.current.scrollTop) + setScrollTop(currTop) } } } @@ -530,9 +510,7 @@ export const CalendarItem = React.forwardRef< } const monthsViewScroll = (e: any) => { - if (monthsData.length <= 1) { - return - } + if (monthsData.length <= 1) return const scrollTop = (e.target as HTMLElement).scrollTop Taro.getEnv() === 'WEB' && setScrollTop(scrollTop) let current = Math.floor(scrollTop / avgHeight) @@ -541,16 +519,10 @@ export const CalendarItem = React.forwardRef< const nextTop = monthsData[current + 1].scrollTop const nextHeight = monthsData[current + 1].cssHeight if (current === 0) { - if (scrollTop >= nextTop) { - current += 1 - } + if (scrollTop >= nextTop) current += 1 } else if (current > 0 && current < monthsNum - 1) { - if (scrollTop >= nextTop) { - current += 1 - } - if (scrollTop < monthsData[current].scrollTop) { - current -= 1 - } + if (scrollTop >= nextTop) current += 1 + if (scrollTop < monthsData[current].scrollTop) current -= 1 } else { const viewPosition = Math.round(scrollTop + viewHeight) if (current + 1 <= monthsNum && viewPosition >= nextTop + nextHeight) { @@ -560,7 +532,6 @@ export const CalendarItem = React.forwardRef< current -= 1 } } - setDefaultRange(monthsNum, current) } @@ -568,151 +539,122 @@ export const CalendarItem = React.forwardRef< scrollToDate, })) + const isDisable = (day: CalendarDay, month: CalendarMonthInfo) => { + if (day.type !== 'active') return true + const dateStr = getCurrDate(day, month) + if (compareDate(dateStr, propStartDate)) return true + if (compareDate(propEndDate, dateStr)) return true + return false + } + const getClasses = (day: CalendarDay, month: CalendarMonthInfo) => { const dateStr = getCurrDate(day, month) - if (day.type === 'active') { - if ( - (propStartDate && Utils.compareDate(dateStr, propStartDate)) || - (propEndDate && Utils.compareDate(propEndDate, dateStr)) - ) { - return `${dayPrefix}-disabled` + if (isDisable(day, month)) return `${dayPrefix}-disabled` + const activeCls = `${dayPrefix}-active` + if (type === 'range' || type === 'week') { + if (isStart(dateStr, currentDate as string[])) + return `${activeCls} active-start` + if (isEnd(dateStr, currentDate as string[])) { + return `${activeCls} active-end` } - if (type === 'range' || type === 'week') { - if ( - isStart(dateStr, currentDate as string[]) || - isEnd(dateStr, currentDate as string[]) - ) { - return `${dayPrefix}-active ${ - isStart(dateStr, currentDate as string[]) ? 'active-start' : '' - } ${isEnd(dateStr, currentDate as string[]) ? 'active-end' : ''}` - } - if ( - Array.isArray(currentDate) && - Object.values(currentDate).length === 2 && - Utils.compareDate(currentDate[0], dateStr) && - Utils.compareDate(dateStr, currentDate[1]) - ) { - if (disableDate(day)) { - return `${dayPrefix}-choose-disabled` - } - return `${dayPrefix}-choose` - } - } else if ( - (type === 'multiple' && isMultiple(dateStr, currentDate as string[])) || - (!Array.isArray(currentDate) && - Utils.isEqual(currentDate as string, dateStr)) + if ( + currentDate.length === 2 && + compareDate(currentDate[0], dateStr) && + compareDate(dateStr, currentDate[1]) ) { - return `${dayPrefix}-active` - } - - if (disableDate(day)) { - return `${dayPrefix}-disabled` + return disableDate(day) + ? `${dayPrefix}-choose-disabled` + : `${dayPrefix}-choose` } - return null + } else if ( + (type === 'multiple' && isMultiple(dateStr, currentDate as string[])) || + (!Array.isArray(currentDate) && isEqual(currentDate, dateStr)) + ) { + return activeCls } - - return `${dayPrefix}-disabled` + if (disableDate(day)) return `${dayPrefix}-disabled` + return null } - const chooseDay = ( + const handleDayClick = ( day: CalendarDay, month: CalendarMonthInfo, - isFirst?: boolean + isFirst: boolean = true ) => { - if (getClasses(day, month) === `${dayPrefix}-disabled`) { - return - } - + if (isDisable(day, month) || disableDate(day)) return const days = [...month.curData] const [y, m] = month.curData - days[2] = - typeof day.day === 'number' ? Utils.getNumTwoBit(day.day) : day.day + days[2] = typeof day.day === 'number' ? getNumTwoBit(day.day) : day.day days[3] = `${days[0]}/${days[1]}/${days[2]}` - days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]) - - if (type === 'multiple') { - if (currentDate.length > 0) { - let hasIndex: any = '' - ;(currentDate as string[]).forEach((item: any, index: number) => { - if (item === days[3]) { - hasIndex = index + days[4] = getWhatDay(+days[0], +days[1], +days[2]) + const newDate = days[3] + + switch (type) { + case 'multiple': { + if (Array.isArray(currentDate)) { + if (currentDate.length > 0) { + const hasIndex = currentDate.findIndex((item) => item === newDate) + if (isFirst) { + state.currDateArray.push([...days]) + } else if (hasIndex > -1) { + currentDate.splice(hasIndex, 1) + state.currDateArray.splice(hasIndex, 1) + } else { + currentDate.push(newDate) + state.currDateArray.push([...days]) + } + } else { + currentDate.push(newDate) + state.currDateArray = [[...days]] } - }) - if (isFirst) { - state.currDateArray.push([...days]) - } else if (hasIndex !== '') { - ;(currentDate as string[]).splice(hasIndex, 1) - state.currDateArray.splice(hasIndex, 1) - } else { - ;(currentDate as string[]).push(days[3]) - state.currDateArray.push([...days]) } - } else { - ;(currentDate as string[]).push(days[3]) - state.currDateArray = [[...days]] + break } - } else if (type === 'range') { - const curDataLength = Object.values(currentDate).length - if (curDataLength === 2 || curDataLength === 0) { - Array.isArray(currentDate) && - currentDate.splice(0) && - currentDate.push(days[3]) - state.currDateArray = [[...days]] - } else if (Utils.compareDate(currentDate[0], days[3])) { - Array.isArray(currentDate) && currentDate.push(days[3]) - state.currDateArray = [...state.currDateArray, [...days]] - } else { - Array.isArray(currentDate) && currentDate.unshift(days[3]) - state.currDateArray = [[...days], ...state.currDateArray] + case 'range': { + if (Array.isArray(currentDate)) { + if (currentDate.length === 2 || currentDate.length === 0) { + currentDate.splice(0, currentDate.length, newDate) + state.currDateArray = [[...days]] + } else if (compareDate(currentDate[0], newDate)) { + currentDate.push(newDate) + state.currDateArray = [...state.currDateArray, [...days]] + } else { + currentDate.unshift(newDate) + state.currDateArray = [[...days], ...state.currDateArray] + } + } + break } - } else if (type === 'week') { - const weekArr = Utils.getWeekDate(y, m, `${day.day}`, firstDayOfWeek) - if (propStartDate && Utils.compareDate(weekArr[0], propStartDate)) { - weekArr.splice(0, 1, propStartDate) + case 'week': { + const weekArr = getWeekDate(y, m, `${day.day}`, firstDayOfWeek) + if (compareDate(weekArr[0], propStartDate)) { + weekArr[0] = propStartDate + } + if (compareDate(propEndDate, weekArr[1])) { + weekArr[1] = propEndDate + } + ;(currentDate as string[]).splice(0, currentDate.length, ...weekArr) + state.currDateArray = [ + formatResultDate(weekArr[0]), + formatResultDate(weekArr[1]), + ] + break } - if (propEndDate && Utils.compareDate(propEndDate, weekArr[1])) { - weekArr.splice(1, 1, propEndDate) + default: { + setCurrentDate(newDate) + state.currDateArray = [...days] + break } - Array.isArray(currentDate) && - currentDate.splice(0) && - currentDate.push(...weekArr) - state.currDateArray = [ - Utils.formatResultDate(weekArr[0]), - Utils.formatResultDate(weekArr[1]), - ] - } else { - setCurrentDate(days[3]) - state.currDateArray = [...days] } - if (!isFirst) { onDayClick && onDayClick(state.currDateArray) if (autoBackfill || !popup) { confirm() } } - setMonthsData(monthsData.slice()) } - const resetSelectedValue = () => { - const itemData = (dateArr: string) => { - days = dateArr.split('/') - days[3] = `${days[0]}/${days[1]}/${days[2]}` - days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]) - return days - } - let days = [] - if (Array.isArray(currentDate) && currentDate) { - days = currentDate.map((item) => { - return itemData(item) - }) - } else { - days = itemData(currentDate as string) - } - return days - } - const confirm = () => { if ( (type === 'range' && state.currDateArray.length === 2) || @@ -727,11 +669,11 @@ export const CalendarItem = React.forwardRef< } const classes = classNames( + classPrefix, { [`${classPrefix}-title`]: !popup, [`${classPrefix}-nofooter`]: !!autoBackfill, }, - classPrefix, className ) @@ -739,6 +681,7 @@ export const CalendarItem = React.forwardRef< [`${classPrefix}-header`]: true, [`${classPrefix}-header-title`]: !popup, }) + // 是否有开始提示 const isStartTip = (day: CalendarDay, month: CalendarMonthInfo) => { return ( @@ -785,6 +728,70 @@ export const CalendarItem = React.forwardRef< ) } + const renderItem = (month: any, day: any, index: number) => { + const startTip = isStartTip(day, month) + const endTip = isEndTip(day, month) + const noStartNorEnd = !startTip && !endTip + return ( +
handleDayClick(day, month, false)} + key={index} + > +
+ {renderDay ? renderDay(day) : day.day} +
+ {!startTip && renderDayTop && ( +
+ {renderDayTop(day)} +
+ )} + {noStartNorEnd && renderDayBottom && ( +
+ {renderDayBottom(day)} +
+ )} + {noStartNorEnd && + isCurrDay(month, day.day) && + !renderDayBottom && + showToday && ( +
+ {locale.calendaritem.today} +
+ )} + {startTip && ( +
+ {startText || locale.calendaritem.start} +
+ )} + {endTip && ( +
+ {endText || locale.calendaritem.end} +
+ )} +
+ ) + } + + const renderPanel = (month: any, key: number) => { + return ( +
+
{month.title}
+
+ {month.monthData.map((day: CalendarDay, i: number) => + renderItem(month, day, i) + )} +
+
+ ) + } + const renderContent = () => { return ( { - return ( -
-
- {month.title} -
-
- {month.monthData.map((day: CalendarDay, i: number) => ( -
{ - chooseDay(day, month) - }} - key={i} - > -
- {renderDay ? renderDay(day) : day.day} -
- {!isStartTip(day, month) && renderDayTop && ( -
- {renderDayTop(day)} -
- )} - {!isStartTip(day, month) && - !isEndTip(day, month) && - renderDayBottom && ( -
- {renderDayBottom(day)} -
- )} - {!isStartTip(day, month) && - !isEndTip(day, month) && - !renderDayBottom && - showToday && - isCurrDay(month, day.day) && ( -
- {locale.calendaritem.today} -
- )} - {isStartTip(day, month) && ( -
- {startText || locale.calendaritem.start} -
- )} - {isEndTip(day, month) && ( -
- {endText || locale.calendaritem.end} -
- )} -
- ))} -
-
- ) + return renderPanel(month, key) })} diff --git a/src/packages/calendaritem/calendaritem.tsx b/src/packages/calendaritem/calendaritem.tsx index 96a33e7f16..d3e605cbd7 100644 --- a/src/packages/calendaritem/calendaritem.tsx +++ b/src/packages/calendaritem/calendaritem.tsx @@ -4,10 +4,17 @@ import classNames from 'classnames' import { PopupProps } from '@/packages/popup/index' import { ComponentDefaults } from '@/utils/typings' import { - Utils, + getDateString, getCurrMonthData, getDaysStatus, getPreMonthDates, + compareDate, + getMonthDays, + getWeekDate, + formatResultDate, + isEqual, + getNumTwoBit, + getWhatDay, } from '@/utils/date' import requestAniFrame from '@/utils/raf' import { useConfig } from '@/packages/configprovider' @@ -70,8 +77,8 @@ const defaultProps = { autoBackfill: false, popup: true, title: '', - startDate: Utils.getDay(0), - endDate: Utils.getDay(365), + startDate: getDateString(0), + endDate: getDateString(365), showToday: true, startText: '', endText: '', @@ -128,6 +135,9 @@ export const CalendarItem = React.forwardRef< onPageChange, } = { ...defaultProps, ...props } + const classPrefix = 'nut-calendar' + const dayPrefix = 'nut-calendar-day' + const weekdays = locale.calendaritem.weekdays const weeks = [ ...weekdays.slice(firstDayOfWeek, 7), @@ -142,24 +152,15 @@ export const CalendarItem = React.forwardRef< const [monthDefaultRange, setMonthDefaultRange] = useState([]) // 初始化开始结束数据 - const propStartDate = (startDate || Utils.getDay(0)) as string - const propEndDate = (endDate || Utils.getDay(365)) as string + const propStartDate = (startDate || getDateString(0)) as string + const propEndDate = (endDate || getDateString(365)) as string const startDates = splitDate(propStartDate) const endDates = splitDate(propEndDate) - const [state] = useState({ currDateArray: [], }) - const getMonthsPanel = () => { - return monthsPanel.current as HTMLDivElement - } - - const getMonthsRef = () => { - return monthsRef.current as HTMLDivElement - } - const resetDefaultValue = () => { if ( defaultValue || @@ -184,14 +185,10 @@ export const CalendarItem = React.forwardRef< const monthsPanel = useRef(null) const viewAreaRef = useRef(null) const [avgHeight, setAvgHeight] = useState(0) - let viewHeight = 0 - const classPrefix = 'nut-calendar' - const dayPrefix = 'nut-calendar-day' - // 获取月数据 - const getMonthData = (curData: string[], monthNum: number, type: string) => { + const getMonthData = (curData: string[], monthNum: number) => { let i = 0 let date = curData const monthData = monthsData @@ -199,11 +196,10 @@ export const CalendarItem = React.forwardRef< const y = parseInt(date[0], 10) const m = parseInt(date[1], 10) const days = [ - ...(getPreMonthDates('prev', y, m, firstDayOfWeek) as CalendarDay[]), - ...(getDaysStatus('active', y, m) as CalendarDay[]), - ] + ...getPreMonthDates('prev', y, m, firstDayOfWeek), + ...getDaysStatus('active', y, m), + ] as CalendarDay[] const cssHeight = 39 + (days.length > 35 ? 384 : 320) - let scrollTop = 0 if (monthData.length > 0) { const monthEle = monthData[monthData.length - 1] @@ -216,40 +212,27 @@ export const CalendarItem = React.forwardRef< cssHeight, scrollTop, } - - if (type === 'next') { - if ( - !endDates || - !Utils.compareDate( - `${endDates[0]}/${endDates[1]}/${Utils.getMonthDays( - endDates[0], - endDates[1] - )}`, - `${curData[0]}/${curData[1]}/${curData[2]}` - ) - ) { - monthData.push(monthInfo) - } - } else if ( - !startDates || - !Utils.compareDate( - `${curData[0]}/${curData[1]}/${curData[2]}`, - `${startDates[0]}/${startDates[1]}/01` + if ( + !endDates || + !compareDate( + `${endDates[0]}/${endDates[1]}/${getMonthDays( + endDates[0], + endDates[1] + )}`, + `${curData[0]}/${curData[1]}/${curData[2]}` ) ) { - monthData.unshift(monthInfo) + monthData.push(monthInfo) } - date = getCurrMonthData('next', y, m) as string[] } while (i++ < monthNum) - setMonthsData(monthData) } const setReachedYearMonthInfo = (current: number) => { const currentMonthsData = monthsData[current] - const [year, month] = currentMonthsData.curData if (currentMonthsData.title === yearMonthTitle) return + const [year, month] = currentMonthsData.curData onPageChange && onPageChange([year, month, `${year}-${month}`]) setYearMonthTitle(currentMonthsData.title) } @@ -278,45 +261,42 @@ export const CalendarItem = React.forwardRef< setReachedYearMonthInfo(current) } - const getMonthNum = () => { - let monthNum = Number(endDates[1]) - Number(startDates[1]) - const yearNum = Number(endDates[0]) - Number(startDates[0]) - if (yearNum > 0) { - monthNum += 12 * yearNum - } - if (monthNum <= 0) { - monthNum = 1 - } - setMonthsNum(monthNum) - return monthNum - } - const setDefaultDate = () => { let defaultData: CalendarValue = [] - // 日期转化为数组,限制初始日期。判断时间范围 - if (type === 'range' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { - if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { - currentDate.splice(0, 1, propStartDate) + if (type === 'single' && typeof currentDate === 'string') { + if (!currentDate.length) { + return defaultData + } + if (compareDate(currentDate, propStartDate)) { + defaultData = [...splitDate(propStartDate)] + } else if (!compareDate(currentDate, propEndDate)) { + defaultData = [...splitDate(propEndDate)] + } else { + defaultData = [...splitDate(currentDate)] + } + return defaultData + } + + if (Array.isArray(currentDate) && currentDate.length) { + // 日期转化为数组,限制初始日期。判断时间范围 + if (type === 'range') { + if (compareDate(currentDate[0], propStartDate)) { + currentDate[0] = propStartDate } - if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { - currentDate.splice(1, 1, propEndDate) + if (compareDate(propEndDate, currentDate[1])) { + currentDate[1] = propEndDate } defaultData = [ ...splitDate(currentDate[0]), ...splitDate(currentDate[1]), ] - } - } else if (type === 'multiple' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { + } else if (type === 'multiple') { const defaultArr = [] as string[] const obj: Record = {} currentDate.forEach((item: string) => { if ( - propStartDate && - !Utils.compareDate(item, propStartDate) && - propEndDate && - !Utils.compareDate(propEndDate, item) + !compareDate(item, propStartDate) && + !compareDate(propEndDate, item) ) { if (!Object.hasOwnProperty.call(obj, item)) { defaultArr.push(item) @@ -324,18 +304,16 @@ export const CalendarItem = React.forwardRef< } } }) - currentDate.splice(0) && currentDate.push(...defaultArr) + currentDate.splice(0, currentDate.length, ...defaultArr) defaultData = [...splitDate(defaultArr[0])] - } - } else if (type === 'week' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { + } else if (type === 'week') { const [y, m, d] = splitDate(currentDate[0]) - const weekArr = Utils.getWeekDate(y, m, d, firstDayOfWeek) - currentDate.splice(0) && currentDate.push(...weekArr) - if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { + const weekArr = getWeekDate(y, m, d, firstDayOfWeek) + currentDate.splice(0, currentDate.length, ...weekArr) + if (compareDate(currentDate[0], propStartDate)) { currentDate.splice(0, 1, propStartDate) } - if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { + if (compareDate(propEndDate, currentDate[1])) { currentDate.splice(1, 1, propEndDate) } defaultData = [ @@ -343,25 +321,8 @@ export const CalendarItem = React.forwardRef< ...splitDate(currentDate[1]), ] } - } else if (currentDate) { - if (currentDate.length > 0) { - if ( - propStartDate && - Utils.compareDate(currentDate as string, propStartDate) - ) { - defaultData = [...splitDate(propStartDate as string)] - } else if ( - propEndDate && - !Utils.compareDate(currentDate as string, propEndDate) - ) { - defaultData = [...splitDate(propEndDate as string)] - } else { - defaultData = [...splitDate(currentDate as string)] - } - } else { - defaultData = [] - } } + return defaultData } @@ -398,53 +359,41 @@ export const CalendarItem = React.forwardRef< } } - const renderCurrentDate = () => { - const defaultData: CalendarValue = setDefaultDate() - const current = getCurrentIndex(defaultData) - - if (defaultData.length > 0) { - // 设置当前选中日期 - if (type === 'range') { - chooseDay( - { day: defaultData[2], type: 'active' }, - monthsData[current.current], - true - ) - chooseDay( - { day: defaultData[5], type: 'active' }, - monthsData[current.lastCurrent], - true - ) - } else if (type === 'week') { - chooseDay( - { day: defaultData[2], type: 'curr' }, - monthsData[current.current], - true + const renderCurrentDate = (defaultData: any, current: any) => { + if (!defaultData.length) return + const date = monthsData[current.current] + // 设置当前选中日期 + if (type === 'range') { + handleDayClick({ day: defaultData[2], type: 'active' }, date) + handleDayClick( + { day: defaultData[5], type: 'active' }, + monthsData[current.lastCurrent] + ) + } else if (type === 'week') { + handleDayClick({ day: defaultData[2], type: 'curr' }, date) + } else if (type === 'multiple') { + ;[...currentDate].forEach((item: string) => { + const dateArr = splitDate(item) + let currentIndex = current.current + currentIndex = monthsData.findIndex( + (item) => item.title === monthTitle(dateArr[0], dateArr[1]) ) - } else if (type === 'multiple') { - ;[...currentDate].forEach((item: string) => { - const dateArr = splitDate(item) - let currentIndex = current.current - monthsData.forEach((item, index) => { - if (item.title === monthTitle(dateArr[0], dateArr[1])) { - currentIndex = index - } - }) - chooseDay( - { day: dateArr[2], type: 'active' }, - monthsData[currentIndex], - true - ) - }) - } else { - chooseDay( - { day: defaultData[2], type: 'active' }, - monthsData[current.current], - true + handleDayClick( + { day: dateArr[2], type: 'active' }, + monthsData[currentIndex] ) - } + }) + } else { + handleDayClick({ day: defaultData[2], type: 'active' }, date) } - return current.current + } + + const getMonthsPanel = () => { + return monthsPanel.current as HTMLDivElement + } + + const getMonthsRef = () => { + return monthsRef.current as HTMLDivElement } const requestAniFrameFunc = (current: number, monthNum: number) => { @@ -459,18 +408,36 @@ export const CalendarItem = React.forwardRef< getMonthsRef().scrollTop = monthsData[current].scrollTop } }) - setAvgHeight(Math.floor(containerHeight / (monthNum + 1))) } + const getMonthNum = () => { + let monthNum = Number(endDates[1]) - Number(startDates[1]) + const yearNum = Number(endDates[0]) - Number(startDates[0]) + if (yearNum > 0) { + monthNum += 12 * yearNum + } + if (monthNum <= 0) { + monthNum = 1 + } + setMonthsNum(monthNum) + return monthNum + } + const initData = () => { // 判断时间范围内存在多少个月 const monthNum = getMonthNum() // 设置月份数据,获取包含月份的所有数据,只需要 set 一次即可。 - getMonthData(startDates, monthNum, 'next') - const current = renderCurrentDate() - setDefaultRange(monthNum, current) - requestAniFrameFunc(current, monthNum) + getMonthData(startDates, monthNum) + // 获取当前默认值 + const defaultData = setDefaultDate() + // 获取当前默认值在的月份 + const current = getCurrentIndex(defaultData) + const currentIndex = current.current + // 渲染第一个默认数据 + renderCurrentDate(defaultData, current) + setDefaultRange(monthNum, currentIndex) + requestAniFrameFunc(currentIndex, monthNum) } useEffect(() => { @@ -493,9 +460,9 @@ export const CalendarItem = React.forwardRef< // 暴露出的API const scrollToDate = (date: string) => { - if (Utils.compareDate(date, propStartDate)) { + if (compareDate(date, propStartDate)) { date = propStartDate - } else if (!Utils.compareDate(date, propEndDate)) { + } else if (!compareDate(date, propEndDate)) { date = propEndDate } const dateArr = splitDate(date) @@ -504,7 +471,6 @@ export const CalendarItem = React.forwardRef< const currTop = monthsData[index].scrollTop if (monthsRef.current) { const distance = currTop - monthsRef.current.scrollTop - if (scrollAnimation) { let flag = 0 const interval = setInterval(() => { @@ -513,7 +479,6 @@ export const CalendarItem = React.forwardRef< const offset = distance / 10 monthsRef.current.scrollTop += offset } - if (flag >= 10) { clearInterval(interval) if (monthsRef.current) { @@ -540,16 +505,10 @@ export const CalendarItem = React.forwardRef< const nextTop = monthsData[current + 1].scrollTop const nextHeight = monthsData[current + 1].cssHeight if (current === 0) { - if (scrollTop >= nextTop) { - current += 1 - } + if (scrollTop >= nextTop) current += 1 } else if (current > 0 && current < monthsNum - 1) { - if (scrollTop >= nextTop) { - current += 1 - } - if (scrollTop < monthsData[current].scrollTop) { - current -= 1 - } + if (scrollTop >= nextTop) current += 1 + if (scrollTop < monthsData[current].scrollTop) current -= 1 } else { const viewPosition = Math.round(scrollTop + viewHeight) if (current + 1 <= monthsNum && viewPosition >= nextTop + nextHeight) { @@ -559,7 +518,6 @@ export const CalendarItem = React.forwardRef< current -= 1 } } - setDefaultRange(monthsNum, current) } @@ -567,120 +525,101 @@ export const CalendarItem = React.forwardRef< scrollToDate, })) - const getClasses = (day: CalendarDay, month: CalendarMonthInfo) => { + const isDisable = (day: CalendarDay, month: CalendarMonthInfo) => { + if (day.type !== 'active') return true const dateStr = getCurrDate(day, month) + if (compareDate(dateStr, propStartDate)) return true + if (compareDate(propEndDate, dateStr)) return true + return false + } - if (day.type === 'active') { - if ( - (propStartDate && Utils.compareDate(dateStr, propStartDate)) || - (propEndDate && Utils.compareDate(propEndDate, dateStr)) - ) { - return `${dayPrefix}-disabled` + const getClasses = (day: CalendarDay, month: CalendarMonthInfo) => { + const dateStr = getCurrDate(day, month) + if (isDisable(day, month)) return `${dayPrefix}-disabled` + const activeCls = `${dayPrefix}-active` + if (type === 'range' || type === 'week') { + if (isStart(dateStr, currentDate as string[])) + return `${activeCls} active-start` + if (isEnd(dateStr, currentDate as string[])) { + return `${activeCls} active-end` } - - if (type === 'range' || type === 'week') { - if ( - isStart(dateStr, currentDate as string[]) || - isEnd(dateStr, currentDate as string[]) - ) { - return `${dayPrefix}-active ${ - isStart(dateStr, currentDate as string[]) ? 'active-start' : '' - } ${isEnd(dateStr, currentDate as string[]) ? 'active-end' : ''}` - } - if ( - Array.isArray(currentDate) && - Object.values(currentDate).length === 2 && - Utils.compareDate(currentDate[0], dateStr) && - Utils.compareDate(dateStr, currentDate[1]) - ) { - if (disableDate(day)) { - return `${dayPrefix}-choose-disabled` - } - return `${dayPrefix}-choose` - } - } else if ( - (type === 'multiple' && isMultiple(dateStr, currentDate as string[])) || - (!Array.isArray(currentDate) && - Utils.isEqual(currentDate as string, dateStr)) + if ( + currentDate.length === 2 && + compareDate(currentDate[0], dateStr) && + compareDate(dateStr, currentDate[1]) ) { - return `${dayPrefix}-active` + return disableDate(day) + ? `${dayPrefix}-choose-disabled` + : `${dayPrefix}-choose` } - - if (disableDate(day)) { - return `${dayPrefix}-disabled` - } - - return null + } else if ( + (type === 'multiple' && isMultiple(dateStr, currentDate as string[])) || + (type === 'single' && isEqual(currentDate as string, dateStr)) + ) { + return activeCls } - - return `${dayPrefix}-disabled` + if (disableDate(day)) return `${dayPrefix}-disabled` + return null } - const chooseDay = ( + const handleDayClick = ( day: CalendarDay, month: CalendarMonthInfo, - isFirst?: boolean + isFirst: boolean = true ) => { if (getClasses(day, month) === `${dayPrefix}-disabled`) { return } - const days = [...month.curData] const [y, m] = month.curData - days[2] = - typeof day.day === 'number' ? Utils.getNumTwoBit(day.day) : day.day + days[2] = typeof day.day === 'number' ? getNumTwoBit(day.day) : day.day days[3] = `${days[0]}/${days[1]}/${days[2]}` - days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]) + days[4] = getWhatDay(+days[0], +days[1], +days[2]) + const newDate = days[3] if (type === 'multiple') { - if (currentDate.length > 0) { - let hasIndex: any = '' - ;(currentDate as string[]).forEach((item: any, index: number) => { - if (item === days[3]) { - hasIndex = index + if (Array.isArray(currentDate)) { + if (currentDate.length > 0) { + const hasIndex = currentDate.findIndex((item) => item === newDate) + if (isFirst) { + state.currDateArray.push([...days]) + } else if (hasIndex > -1) { + currentDate.splice(hasIndex, 1) + state.currDateArray.splice(hasIndex, 1) + } else { + currentDate.push(newDate) + state.currDateArray.push([...days]) } - }) - if (isFirst) { - state.currDateArray.push([...days]) - } else if (hasIndex !== '') { - ;(currentDate as string[]).splice(hasIndex, 1) - state.currDateArray.splice(hasIndex, 1) } else { - ;(currentDate as string[]).push(days[3]) - state.currDateArray.push([...days]) + currentDate.push(newDate) + state.currDateArray = [[...days]] } - } else { - ;(currentDate as string[]).push(days[3]) - state.currDateArray = [[...days]] } } else if (type === 'range') { - const curDataLength = Object.values(currentDate).length - if (curDataLength === 2 || curDataLength === 0) { - Array.isArray(currentDate) && - currentDate.splice(0) && - currentDate.push(days[3]) - state.currDateArray = [[...days]] - } else if (Utils.compareDate(currentDate[0], days[3])) { - Array.isArray(currentDate) && currentDate.push(days[3]) - state.currDateArray = [...state.currDateArray, [...days]] - } else { - Array.isArray(currentDate) && currentDate.unshift(days[3]) - state.currDateArray = [[...days], ...state.currDateArray] + if (Array.isArray(currentDate)) { + if (currentDate.length === 2 || currentDate.length === 0) { + currentDate.splice(0, currentDate.length, newDate) + state.currDateArray = [[...days]] + } else if (compareDate(currentDate[0], newDate)) { + currentDate.push(newDate) + state.currDateArray = [...state.currDateArray, [...days]] + } else { + currentDate.unshift(newDate) + state.currDateArray = [[...days], ...state.currDateArray] + } } } else if (type === 'week') { - const weekArr = Utils.getWeekDate(y, m, `${day.day}`, firstDayOfWeek) - if (propStartDate && Utils.compareDate(weekArr[0], propStartDate)) { - weekArr.splice(0, 1, propStartDate) + const weekArr = getWeekDate(y, m, `${day.day}`, firstDayOfWeek) + if (compareDate(weekArr[0], propStartDate)) { + weekArr[0] = propStartDate } - if (propEndDate && Utils.compareDate(propEndDate, weekArr[1])) { - weekArr.splice(1, 1, propEndDate) + if (compareDate(propEndDate, weekArr[1])) { + weekArr[1] = propEndDate } - Array.isArray(currentDate) && - currentDate.splice(0) && - currentDate.push(...weekArr) + ;(currentDate as string[]).splice(0, currentDate.length, ...weekArr) state.currDateArray = [ - Utils.formatResultDate(weekArr[0]), - Utils.formatResultDate(weekArr[1]), + formatResultDate(weekArr[0]), + formatResultDate(weekArr[1]), ] } else { setCurrentDate(days[3]) @@ -693,28 +632,9 @@ export const CalendarItem = React.forwardRef< confirm() } } - setMonthsData(monthsData.slice()) } - const resetSelectedValue = () => { - const itemData = (dateArr: string) => { - days = dateArr.split('/') - days[3] = `${days[0]}/${days[1]}/${days[2]}` - days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]) - return days - } - let days = [] - if (Array.isArray(currentDate) && currentDate) { - days = currentDate.map((item) => { - return itemData(item) - }) - } else { - days = itemData(currentDate as string) - } - return days - } - const confirm = () => { if ( (type === 'range' && state.currDateArray.length === 2) || @@ -729,11 +649,11 @@ export const CalendarItem = React.forwardRef< } const classes = classNames( + classPrefix, { [`${classPrefix}-title`]: !popup, [`${classPrefix}-nofooter`]: !!autoBackfill, }, - classPrefix, className ) @@ -788,6 +708,70 @@ export const CalendarItem = React.forwardRef< ) } + const renderItem = (month: any, day: any, index: number) => { + const startTip = isStartTip(day, month) + const endTip = isEndTip(day, month) + const noStartNorEnd = !startTip && !endTip + return ( +
handleDayClick(day, month, false)} + key={index} + > +
+ {renderDay ? renderDay(day) : day.day} +
+ {!startTip && renderDayTop && ( +
+ {renderDayTop(day)} +
+ )} + {noStartNorEnd && renderDayBottom && ( +
+ {renderDayBottom(day)} +
+ )} + {noStartNorEnd && + !renderDayBottom && + showToday && + isCurrDay(month, day.day) && ( +
+ {locale.calendaritem.today} +
+ )} + {startTip && ( +
+ {startText || locale.calendaritem.start} +
+ )} + {endTip && ( +
+ {endText || locale.calendaritem.end} +
+ )} +
+ ) + } + + const renderPanel = (month: any, key: number) => { + return ( +
+
{month.title}
+
+ {month.monthData.map((day: CalendarDay, i: number) => + renderItem(month, day, i) + )} +
+
+ ) + } + const renderContent = () => { return (
{ - return ( -
-
- {month.title} -
-
- {month.monthData.map((day: CalendarDay, i: number) => ( -
{ - chooseDay(day, month) - }} - key={i} - > -
- {renderDay ? renderDay(day) : day.day} -
- {!isStartTip(day, month) && renderDayTop && ( -
- {renderDayTop(day)} -
- )} - {!isStartTip(day, month) && - !isEndTip(day, month) && - renderDayBottom && ( -
- {renderDayBottom(day)} -
- )} - {!isStartTip(day, month) && - !isEndTip(day, month) && - !renderDayBottom && - showToday && - isCurrDay(month, day.day) && ( -
- {locale.calendaritem.today} -
- )} - {isStartTip(day, month) && ( -
- {startText || locale.calendaritem.start} -
- )} - {isEndTip(day, month) && ( -
- {endText || locale.calendaritem.end} -
- )} -
- ))} -
-
- ) + return renderPanel(month, key) })}
diff --git a/src/utils/date.ts b/src/utils/date.ts index 5fe0b4db83..c594246240 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,224 +1,204 @@ -export const Utils = { - /** - * 是否为闫年 - * @return {Boolse} true|false - */ - isLeapYear(y: number): boolean { - return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 - }, +/** + * 判断是否为闰年 + * 规则: + * 1. 能被4整除但不能被100整除,或 + * 2. 能被400整除 + * @param {number} y - 年份 + * @return {Boolse} true|false + */ +export const isLeapYear = (y: number): boolean => { + return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 +} - /** - * 返回星期数 - * @return {String} - */ - getWhatDay(year: number, month: number, day: number): string { - const date = new Date(`${year}/${month}/${day}`) - const index = date.getDay() - const dayNames = [ - '星期日', - '星期一', - '星期二', - '星期三', - '星期四', - '星期五', - '星期六', - ] - return dayNames[index] - }, +/** + * 返回星期数 + * @return {String} + */ +export const getWhatDay = ( + year: number, + month: number, + day: number +): string => { + const date = new Date(year, month - 1, day) // 月份从0开始 + const dayNames = [ + '星期日', + '星期一', + '星期二', + '星期三', + '星期四', + '星期五', + '星期六', + ] + return dayNames[date.getDay()] +} - /** - * 返回上一个月在当前面板中的天数 - * @return {Number} - */ - getMonthPreDay(year: number, month: number): number { - const date = new Date(`${year}/${month}/01`) - let day = date.getDay() - if (day === 0) { - day = 7 - } - return day - }, +/** + * 返回上一个月在当前面板中的天数 + * @return {Number} + */ +export const getMonthPreDay = (year: number, month: number): number => { + const day = new Date(year, month - 1, 1).getDay() // 月份从0开始 + return day === 0 ? 7 : day // 将周日从0改为7 +} - /** - * 返回月份天数 - * @return {Number} - */ - getMonthDays(year: string, month: string): number { - if (/^0/.test(month)) { - month = month.split('')[1] - } - return ( - [ - 0, - 31, - this.isLeapYear(Number(year)) ? 29 : 28, - 31, - 30, - 31, - 30, - 31, - 31, - 30, - 31, - 30, - 31, - ] as number[] - )[month as any] - }, +/** + * 返回月份天数 + * @return {Number} + */ +export const getMonthDays = (year: string, month: string): number => { + if (/^0/.test(month)) { + month = month.split('')[1] + } + return ( + [ + 0, + 31, + isLeapYear(Number(year)) ? 29 : 28, + 31, + 30, + 31, + 30, + 31, + 31, + 30, + 31, + 30, + 31, + ] as number[] + )[month as any] +} - /** - * 补齐数字位数 - * @return {string} - */ - getNumTwoBit(n: number): string { - n = Number(n) - return (n > 9 ? '' : '0') + n - }, +/** + * 补齐数字位数 + * @return {string} + */ +export const getNumTwoBit = (n: number): string => { + return n > 9 ? `${n}` : `0${n}` +} - /** - * 日期对象转成字符串 - * @return {string} - */ - date2Str(date: Date, split?: string): string { - split = split || '-' - const y = date.getFullYear() - const m = this.getNumTwoBit(date.getMonth() + 1) - const d = this.getNumTwoBit(date.getDate()) - return [y, m, d].join(split) - }, +/** + * 日期对象转成字符串 + * @return {string} + */ +export const date2Str = (date: Date, split: string = '-'): string => { + const y = date.getFullYear() + const m = getNumTwoBit(date.getMonth() + 1) + const d = getNumTwoBit(date.getDate()) + return [y, m, d].join(split) +} - /** - * 返回日期格式字符串 - * @param {Number} 0返回今天的日期、1返回明天的日期,2返回后天得日期,依次类推 - * @return {string} '2014-12-31' - */ - getDay(i: number): string { - i = i || 0 - let date = new Date() - const diff = i * (1000 * 60 * 60 * 24) - date = new Date(date.getTime() + diff) - return this.date2Str(date) - }, +/** + * 返回日期格式字符串 + * @param {Number} 0返回今天的日期、1返回明天的日期,2返回后天得日期,依次类推 + * @return {string} '2014-12-31' + */ +export const getDateString = (offset: number = 0): string => { + const date = new Date() + date.setDate(date.getDate() + offset) + return date2Str(date, '-') +} - /** - * 时间比较 - * @return {Boolean} - */ - compareDate(date1: string, date2: string): boolean { - const startTime = new Date(date1.replace('-', '/').replace('-', '/')) - const endTime = new Date(date2.replace('-', '/').replace('-', '/')) - if (startTime >= endTime) { - return false - } - return true - }, +/** + * 时间比较 + * @return {Boolean} + */ +export const compareDate = (date1: string, date2: string): boolean => { + const startTime = new Date(date1.replace('-', '/').replace('-', '/')) + const endTime = new Date(date2.replace('-', '/').replace('-', '/')) + return startTime < endTime +} - /** - * 时间是否相等 - * @return {Boolean} - */ - isEqual(date1: string, date2: string): boolean { - const startTime = new Date((date1 || '').replace(/-/g, '/')).getTime() - const endTime = new Date(date2.replace(/-/g, '/')).getTime() - if (startTime === endTime) { - return true - } - return false - }, - getMonthWeek( - year: string, - month: string, - date: string, - firstDayOfWeek = 0 - ): number { - const dateNow = new Date(Number(year), parseInt(month) - 1, Number(date)) - let w = dateNow.getDay() // 星期数 - const d = dateNow.getDate() - let remainder = 6 - w - if (firstDayOfWeek !== 0) { - w = w === 0 ? 7 : w - remainder = 7 - w - } - return Math.ceil((d + remainder) / 7) - }, - getYearWeek( - year: string, - month: string, - date: string, - firstDayOfWeek = 0 - ): number { - const dateNow = new Date(Number(year), parseInt(month) - 1, Number(date)) - const dateFirst = new Date(Number(year), 0, 1) - const dataNumber = Math.round( - (dateNow.valueOf() - dateFirst.valueOf()) / 86400000 - ) - return Math.ceil((dataNumber + (dateFirst.getDay() + 1 - 1)) / 7) - }, - getWeekDate( - year: string, - month: string, - date: string, - firstDayOfWeek = 0 - ): string[] { - const dateNow = new Date(Number(year), parseInt(month) - 1, Number(date)) - const nowTime = dateNow.getTime() - let day = dateNow.getDay() - if (firstDayOfWeek === 0) { - const oneDayTime = 24 * 60 * 60 * 1000 - // 显示周日 - const SundayTime = nowTime - day * oneDayTime // 本周的周日 - // 显示周六 - const SaturdayTime = nowTime + (6 - day) * oneDayTime // 本周的周六 +/** + * 时间是否相等 + * @return {Boolean} + */ +export const isEqual = (date1: string, date2: string): boolean => { + const startTime = new Date((date1 || '').replace(/-/g, '/')).getTime() + const endTime = new Date(date2.replace(/-/g, '/')).getTime() + return startTime === endTime +} - const sunday = this.date2Str(new Date(SundayTime)) - const saturday = this.date2Str(new Date(SaturdayTime)) - return [sunday, saturday] - } - day = day === 0 ? 7 : day +export const getMonthWeek = ( + year: number, + month: number, + date: number, + firstDayOfWeek = 0 +): number => { + const dateNow = new Date(year, month - 1, date) + let w = dateNow.getDay() // 星期数 + let remainder = 6 - w + if (firstDayOfWeek !== 0) { + w = w === 0 ? 7 : w + remainder = 7 - w + } + return Math.ceil((date + remainder) / 7) +} +export const getYearWeek = ( + year: number, + month: number, + date: number, + firstDayOfWeek = 0 +): number => { + const dateNow = new Date(year, month - 1, date) + const dateFirst = new Date(year, 0, 1) + const dataNumber = Math.round( + (dateNow.valueOf() - dateFirst.valueOf()) / 86400000 + ) + return Math.ceil((dataNumber + (dateFirst.getDay() + 1 - 1)) / 7) +} +export const getWeekDate = ( + year: string, + month: string, + date: string, + firstDayOfWeek = 0 +): string[] => { + const dateNow = new Date(Number(year), parseInt(month) - 1, Number(date)) + const nowTime = dateNow.getTime() + let day = dateNow.getDay() + if (firstDayOfWeek === 0) { const oneDayTime = 24 * 60 * 60 * 1000 - // 显示周一 - const MondayTime = nowTime - (day - 1) * oneDayTime // 本周的周一 // 显示周日 - const SundayTime = nowTime + (7 - day) * oneDayTime // 本周的周日 - - const monday = this.date2Str(new Date(MondayTime)) - const sunday = this.date2Str(new Date(SundayTime)) - return [monday, sunday] - }, + const SundayTime = nowTime - day * oneDayTime // 本周的周日 + // 显示周六 + const SaturdayTime = nowTime + (6 - day) * oneDayTime // 本周的周六 + const sunday = date2Str(new Date(SundayTime)) + const saturday = date2Str(new Date(SaturdayTime)) + return [sunday, saturday] + } + day = day === 0 ? 7 : day + const oneDayTime = 24 * 60 * 60 * 1000 + // 显示周一 + const MondayTime = nowTime - (day - 1) * oneDayTime // 本周的周一 + // 显示周日 + const SundayTime = nowTime + (7 - day) * oneDayTime // 本周的周日 + const monday = date2Str(new Date(MondayTime)) + const sunday = date2Str(new Date(SundayTime)) + return [monday, sunday] +} - formatResultDate(date: string) { - const days = [...date.split('-')] - days[2] = Utils.getNumTwoBit(Number(days[2])) - days[3] = `${days[0]}-${days[1]}-${days[2]}` - days[4] = Utils.getWhatDay(+days[0], +days[1], +days[2]) - return days - }, +export const formatResultDate = (date: string) => { + const [year, month, day] = [...date.split('-')] + const formatterDay = getNumTwoBit(Number(day)) + const formatterDate = `${year}-${month}-${day}` + const dayOfWeek = getWhatDay(Number(year), Number(month), Number(day)) + return [year, month, formatterDay, formatterDate, dayOfWeek] } // 获取当前月数据 export const getCurrMonthData = (type: string, year: number, month: number) => { - switch (type) { - case 'prev': - month === 1 && (year -= 1) - month = month === 1 ? 12 : --month - break - case 'next': - month === 12 && (year += 1) - month = month === 12 ? 1 : ++month - break - default: - break + if (type === 'prev') { + month === 1 && (year -= 1) + month = month === 1 ? 12 : --month + } else if (type === 'next') { + month === 12 && (year += 1) + month = month === 12 ? 1 : ++month } - return [ - year, - Utils.getNumTwoBit(month), - Utils.getMonthDays(String(year), String(month)), - ] + return [year, getNumTwoBit(month), getMonthDays(String(year), String(month))] } // 获取日期状态 export const getDaysStatus = (type: string, year: number, month: number) => { - let days = Utils.getMonthDays(`${year}`, `${month}`) + let days = getMonthDays(`${year}`, `${month}`) // 修复:当某个月的1号是周日时,月份下方会空出来一行 if (type === 'prev' && days >= 7) { days -= 7 @@ -246,14 +226,14 @@ export const getPreMonthDates = ( preMonth = 12 preYear += 1 } - let days = Utils.getMonthPreDay(+year, +month) + let days = getMonthPreDay(+year, +month) days -= firstDayOfWeek // 修复:当某个月的1号是周日时,月份下方会空出来一行 if (type === 'prev' && days >= 7) { days -= 7 } - const preDates = Utils.getMonthDays(`${preYear}`, `${preMonth}`) + const preDates = getMonthDays(`${preYear}`, `${preMonth}`) const months = Array.from(Array(preDates), (v, k) => { return { day: k + 1,