From d4a51a02cee5d5739981880e0e7ea08b4699faff Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 11 Feb 2025 13:37:03 +0800 Subject: [PATCH 1/5] refactor: calendar --- src/packages/calendar/calendar.scss | 18 +- src/packages/calendar/calendar.taro.tsx | 6 +- src/packages/calendar/calendar.tsx | 6 +- src/packages/calendar/demos/taro/demo1.tsx | 3 - src/packages/calendar/utils.tsx | 16 +- src/packages/calendarcard/utils.ts | 8 +- .../calendaritem/calendaritem.taro.tsx | 688 ++++++++---------- src/packages/calendaritem/calendaritem.tsx | 127 ++-- src/utils/date.ts | 378 +++++----- 9 files changed, 575 insertions(+), 675 deletions(-) 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..1f1748c8a4 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 { getDay } 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: getDay(0), + endDate: getDay(365), showToday: true, startText: '', endText: '', diff --git a/src/packages/calendar/calendar.tsx b/src/packages/calendar/calendar.tsx index 327a1109a5..c31a06bb43 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 { getDay } 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: getDay(0), + endDate: getDay(365), showToday: true, startText: '', endText: '', 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/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..3cb5d5aa97 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, + getDay, 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: getDay(0), + endDate: getDay(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 || getDay(0)) as string + const propEndDate = (endDate || getDay(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,73 @@ 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 + 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 > 0) { + 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 + case 'multiple': + // eslint-disable-next-line no-case-declarations + const defaultArr = [] as string[] + // eslint-disable-next-line no-case-declarations + 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 + case 'week': + // eslint-disable-next-line no-case-declarations + const [y, m, d] = splitDate(currentDate[0]) + // eslint-disable-next-line no-case-declarations + const weekArr = getWeekDate(y, m, d, firstDayOfWeek) + currentDate.splice(0, currentDate.length, ...weekArr) + if (compareDate(currentDate[0], propStartDate)) { + currentDate.splice(0, 1, propStartDate) } - }) - currentDate.splice(0) && currentDate.push(...defaultArr) - defaultData = [...splitDate(defaultArr[0])] - } - } 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) - } - if (propEndDate && Utils.compareDate(propEndDate, currentDate[1])) { - currentDate.splice(1, 1, propEndDate) - } - 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)] - } - } else { - defaultData = [] + if (compareDate(propEndDate, currentDate[1])) { + currentDate.splice(1, 1, propEndDate) + } + defaultData = [ + ...splitDate(currentDate[0]), + ...splitDate(currentDate[1]), + ] + break + default: + break } } return defaultData @@ -385,12 +356,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 +367,94 @@ 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 +470,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 +489,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 +507,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 +516,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 +529,6 @@ export const CalendarItem = React.forwardRef< current -= 1 } } - setDefaultRange(monthsNum, current) } @@ -568,151 +536,119 @@ 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 && 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]] - } - } 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] - } - } 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) - } - if (propEndDate && Utils.compareDate(propEndDate, weekArr[1])) { - weekArr.splice(1, 1, propEndDate) - } - 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] + break + 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 + case 'week': + // eslint-disable-next-line no-case-declarations + 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 + default: + setCurrentDate(newDate) + state.currDateArray = [...days] + break } - 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 +663,11 @@ export const CalendarItem = React.forwardRef< } const classes = classNames( + classPrefix, { [`${classPrefix}-title`]: !popup, [`${classPrefix}-nofooter`]: !!autoBackfill, }, - classPrefix, className ) @@ -739,6 +675,7 @@ export const CalendarItem = React.forwardRef< [`${classPrefix}-header`]: true, [`${classPrefix}-header-title`]: !popup, }) + // 是否有开始提示 const isStartTip = (day: CalendarDay, month: CalendarMonthInfo) => { return ( @@ -785,6 +722,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..bf75aefed5 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, + getDay, 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: getDay(0), + endDate: getDay(365), showToday: true, startText: '', endText: '', @@ -142,8 +149,8 @@ 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 || getDay(0)) as string + const propEndDate = (endDate || getDay(365)) as string const startDates = splitDate(propStartDate) const endDates = splitDate(propEndDate) @@ -191,7 +198,7 @@ export const CalendarItem = React.forwardRef< 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 @@ -216,30 +223,18 @@ 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) @@ -296,10 +291,10 @@ export const CalendarItem = React.forwardRef< // 日期转化为数组,限制初始日期。判断时间范围 if (type === 'range' && Array.isArray(currentDate)) { if (currentDate.length > 0) { - if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { + 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 = [ @@ -314,9 +309,9 @@ export const CalendarItem = React.forwardRef< currentDate.forEach((item: string) => { if ( propStartDate && - !Utils.compareDate(item, propStartDate) && + !compareDate(item, propStartDate) && propEndDate && - !Utils.compareDate(propEndDate, item) + !compareDate(propEndDate, item) ) { if (!Object.hasOwnProperty.call(obj, item)) { defaultArr.push(item) @@ -330,12 +325,12 @@ export const CalendarItem = React.forwardRef< } 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) + const weekArr = getWeekDate(y, m, d, firstDayOfWeek) currentDate.splice(0) && currentDate.push(...weekArr) - if (propStartDate && Utils.compareDate(currentDate[0], propStartDate)) { + 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 = [ @@ -347,12 +342,12 @@ export const CalendarItem = React.forwardRef< if (currentDate.length > 0) { if ( propStartDate && - Utils.compareDate(currentDate as string, propStartDate) + compareDate(currentDate as string, propStartDate) ) { defaultData = [...splitDate(propStartDate as string)] } else if ( propEndDate && - !Utils.compareDate(currentDate as string, propEndDate) + !compareDate(currentDate as string, propEndDate) ) { defaultData = [...splitDate(propEndDate as string)] } else { @@ -467,7 +462,7 @@ export const CalendarItem = React.forwardRef< // 判断时间范围内存在多少个月 const monthNum = getMonthNum() // 设置月份数据,获取包含月份的所有数据,只需要 set 一次即可。 - getMonthData(startDates, monthNum, 'next') + getMonthData(startDates, monthNum) const current = renderCurrentDate() setDefaultRange(monthNum, current) requestAniFrameFunc(current, monthNum) @@ -493,9 +488,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) @@ -559,7 +554,6 @@ export const CalendarItem = React.forwardRef< current -= 1 } } - setDefaultRange(monthsNum, current) } @@ -569,15 +563,13 @@ export const CalendarItem = React.forwardRef< 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)) + compareDate(dateStr, propStartDate) || + compareDate(propEndDate, dateStr) ) { return `${dayPrefix}-disabled` } - if (type === 'range' || type === 'week') { if ( isStart(dateStr, currentDate as string[]) || @@ -590,8 +582,8 @@ export const CalendarItem = React.forwardRef< if ( Array.isArray(currentDate) && Object.values(currentDate).length === 2 && - Utils.compareDate(currentDate[0], dateStr) && - Utils.compareDate(dateStr, currentDate[1]) + compareDate(currentDate[0], dateStr) && + compareDate(dateStr, currentDate[1]) ) { if (disableDate(day)) { return `${dayPrefix}-choose-disabled` @@ -600,19 +592,15 @@ export const CalendarItem = React.forwardRef< } } else if ( (type === 'multiple' && isMultiple(dateStr, currentDate as string[])) || - (!Array.isArray(currentDate) && - Utils.isEqual(currentDate as string, dateStr)) + (!Array.isArray(currentDate) && isEqual(currentDate as string, dateStr)) ) { return `${dayPrefix}-active` } - if (disableDate(day)) { return `${dayPrefix}-disabled` } - return null } - return `${dayPrefix}-disabled` } @@ -624,13 +612,11 @@ export const CalendarItem = React.forwardRef< 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]) if (type === 'multiple') { if (currentDate.length > 0) { @@ -660,7 +646,7 @@ export const CalendarItem = React.forwardRef< currentDate.splice(0) && currentDate.push(days[3]) state.currDateArray = [[...days]] - } else if (Utils.compareDate(currentDate[0], days[3])) { + } else if (compareDate(currentDate[0], days[3])) { Array.isArray(currentDate) && currentDate.push(days[3]) state.currDateArray = [...state.currDateArray, [...days]] } else { @@ -668,19 +654,19 @@ export const CalendarItem = React.forwardRef< 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)) { + const weekArr = getWeekDate(y, m, `${day.day}`, firstDayOfWeek) + if (compareDate(weekArr[0], propStartDate)) { weekArr.splice(0, 1, propStartDate) } - if (propEndDate && Utils.compareDate(propEndDate, weekArr[1])) { + if (compareDate(propEndDate, weekArr[1])) { weekArr.splice(1, 1, propEndDate) } Array.isArray(currentDate) && currentDate.splice(0) && currentDate.push(...weekArr) state.currDateArray = [ - Utils.formatResultDate(weekArr[0]), - Utils.formatResultDate(weekArr[1]), + formatResultDate(weekArr[0]), + formatResultDate(weekArr[1]), ] } else { setCurrentDate(days[3]) @@ -693,28 +679,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) || diff --git a/src/utils/date.ts b/src/utils/date.ts index 5fe0b4db83..47469388b9 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,198 +1,200 @@ -export const Utils = { - /** - * 是否为闫年 - * @return {Boolse} true|false - */ - 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 {Boolse} true|false + */ +export const isLeapYear = (y: number): boolean => { + return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 +} - /** - * 返回上一个月在当前面板中的天数 - * @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 {String} + */ +export const 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 {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 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 {string} - */ - getNumTwoBit(n: number): string { - n = Number(n) - return (n > 9 ? '' : '0') + n - }, +/** + * 返回月份天数 + * @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} - */ - 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 getNumTwoBit = (n: number): string => { + n = Number(n) + return (n > 9 ? '' : '0') + n +} - /** - * 返回日期格式字符串 - * @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) - }, +/** + * 日期对象转成字符串 + * @return {string} + */ +export const date2Str = (date: Date, split?: string): string => { + split = split || '-' + const y = date.getFullYear() + const m = getNumTwoBit(date.getMonth() + 1) + const d = getNumTwoBit(date.getDate()) + return [y, m, d].join(split) +} - /** - * 时间比较 - * @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 - }, +/** + * 返回日期格式字符串 + * @param {Number} 0返回今天的日期、1返回明天的日期,2返回后天得日期,依次类推 + * @return {string} '2014-12-31' + */ +export const 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) +} - /** - * 时间是否相等 - * @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 {Boolean} + */ +export const 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 - }, - 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 true +} - const sunday = this.date2Str(new Date(SundayTime)) - const saturday = this.date2Str(new Date(SaturdayTime)) - return [sunday, saturday] - } - day = day === 0 ? 7 : day +/** + * 时间是否相等 + * @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() + if (startTime === endTime) { + return true + } + return false +} +export const 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) +} +export const 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) +} +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 SundayTime = nowTime - day * oneDayTime // 本周的周日 + // 显示周六 + const SaturdayTime = nowTime + (6 - day) * oneDayTime // 本周的周六 - const monday = this.date2Str(new Date(MondayTime)) - const sunday = this.date2Str(new Date(SundayTime)) - return [monday, sunday] - }, + 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 days = [...date.split('-')] + days[2] = getNumTwoBit(Number(days[2])) + days[3] = `${days[0]}-${days[1]}-${days[2]}` + days[4] = getWhatDay(+days[0], +days[1], +days[2]) + return days } // 获取当前月数据 @@ -209,16 +211,12 @@ export const getCurrMonthData = (type: string, year: number, month: number) => { default: break } - 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 +244,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, From 99c272bbadd96c3ca3edf588b58e50e9c4544f11 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 11 Feb 2025 14:35:32 +0800 Subject: [PATCH 2/5] refactor: calendar h5 --- .../calendaritem/calendaritem.taro.tsx | 4 +- src/packages/calendaritem/calendaritem.tsx | 413 ++++++++---------- 2 files changed, 190 insertions(+), 227 deletions(-) diff --git a/src/packages/calendaritem/calendaritem.taro.tsx b/src/packages/calendaritem/calendaritem.taro.tsx index 3cb5d5aa97..c760c9568e 100644 --- a/src/packages/calendaritem/calendaritem.taro.tsx +++ b/src/packages/calendaritem/calendaritem.taro.tsx @@ -279,7 +279,7 @@ export const CalendarItem = React.forwardRef< } return defaultData } - if (Array.isArray(currentDate) && currentDate.length > 0) { + if (Array.isArray(currentDate) && currentDate.length) { switch (type) { case 'range': if (compareDate(currentDate[0], propStartDate)) { @@ -569,7 +569,7 @@ export const CalendarItem = React.forwardRef< ) { return activeCls } - if (disableDate && disableDate(day)) return `${dayPrefix}-disabled` + if (disableDate(day)) return `${dayPrefix}-disabled` return null } diff --git a/src/packages/calendaritem/calendaritem.tsx b/src/packages/calendaritem/calendaritem.tsx index bf75aefed5..cb8b7f39e3 100644 --- a/src/packages/calendaritem/calendaritem.tsx +++ b/src/packages/calendaritem/calendaritem.tsx @@ -135,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), @@ -154,7 +157,6 @@ export const CalendarItem = React.forwardRef< const startDates = splitDate(propStartDate) const endDates = splitDate(propEndDate) - const [state] = useState({ currDateArray: [], }) @@ -191,12 +193,8 @@ 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) => { let i = 0 @@ -206,11 +204,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] @@ -237,7 +234,6 @@ export const CalendarItem = React.forwardRef< } date = getCurrMonthData('next', y, m) as string[] } while (i++ < monthNum) - setMonthsData(monthData) } @@ -288,29 +284,39 @@ export const CalendarItem = React.forwardRef< const setDefaultDate = () => { let defaultData: CalendarValue = [] - // 日期转化为数组,限制初始日期。判断时间范围 - if (type === 'range' && Array.isArray(currentDate)) { - if (currentDate.length > 0) { + 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.splice(0, 1, propStartDate) + currentDate[0] = propStartDate } if (compareDate(propEndDate, currentDate[1])) { - currentDate.splice(1, 1, propEndDate) + 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 && !compareDate(item, propStartDate) && - propEndDate && !compareDate(propEndDate, item) ) { if (!Object.hasOwnProperty.call(obj, item)) { @@ -319,14 +325,12 @@ 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 = getWeekDate(y, m, d, firstDayOfWeek) - currentDate.splice(0) && currentDate.push(...weekArr) + currentDate.splice(0, currentDate.length, ...weekArr) if (compareDate(currentDate[0], propStartDate)) { currentDate.splice(0, 1, propStartDate) } @@ -338,25 +342,8 @@ export const CalendarItem = React.forwardRef< ...splitDate(currentDate[1]), ] } - } else if (currentDate) { - if (currentDate.length > 0) { - if ( - propStartDate && - compareDate(currentDate as string, propStartDate) - ) { - defaultData = [...splitDate(propStartDate as string)] - } else if ( - propEndDate && - !compareDate(currentDate as string, propEndDate) - ) { - defaultData = [...splitDate(propEndDate as string)] - } else { - defaultData = [...splitDate(currentDate as string)] - } - } else { - defaultData = [] - } } + return defaultData } @@ -393,53 +380,33 @@ 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 requestAniFrameFunc = (current: number, monthNum: number) => { @@ -463,9 +430,15 @@ export const CalendarItem = React.forwardRef< const monthNum = getMonthNum() // 设置月份数据,获取包含月份的所有数据,只需要 set 一次即可。 getMonthData(startDates, monthNum) - const current = renderCurrentDate() - setDefaultRange(monthNum, current) - requestAniFrameFunc(current, monthNum) + // 获取当前默认值 + const defaultData = setDefaultDate() + // 获取当前默认值在的月份 + const current = getCurrentIndex(defaultData) + const currentIndex = current.current + // 渲染第一个默认数据 + renderCurrentDate(defaultData, current) + setDefaultRange(monthNum, currentIndex) + requestAniFrameFunc(currentIndex, monthNum) } useEffect(() => { @@ -499,7 +472,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(() => { @@ -508,7 +480,6 @@ export const CalendarItem = React.forwardRef< const offset = distance / 10 monthsRef.current.scrollTop += offset } - if (flag >= 10) { clearInterval(interval) if (monthsRef.current) { @@ -561,53 +532,47 @@ 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 ( - compareDate(dateStr, propStartDate) || - 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 && - compareDate(currentDate[0], dateStr) && - 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) && 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[])) || + (!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 @@ -617,53 +582,48 @@ export const CalendarItem = React.forwardRef< days[2] = typeof day.day === 'number' ? getNumTwoBit(day.day) : day.day days[3] = `${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 (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 = getWeekDate(y, m, `${day.day}`, firstDayOfWeek) if (compareDate(weekArr[0], propStartDate)) { - weekArr.splice(0, 1, propStartDate) + weekArr[0] = propStartDate } if (compareDate(propEndDate, weekArr[1])) { - weekArr.splice(1, 1, propEndDate) + weekArr[1] = propEndDate } - Array.isArray(currentDate) && - currentDate.splice(0) && - currentDate.push(...weekArr) + ;(currentDate as string[]).splice(0, currentDate.length, ...weekArr) state.currDateArray = [ formatResultDate(weekArr[0]), formatResultDate(weekArr[1]), @@ -696,11 +656,11 @@ export const CalendarItem = React.forwardRef< } const classes = classNames( + classPrefix, { [`${classPrefix}-title`]: !popup, [`${classPrefix}-nofooter`]: !!autoBackfill, }, - classPrefix, className ) @@ -755,6 +715,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) })}
From 635f37b66e66ae9277531dd51cfac73838c8749c Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Tue, 11 Feb 2025 14:49:27 +0800 Subject: [PATCH 3/5] refactor: calendar h5 --- src/packages/calendaritem/calendaritem.tsx | 59 ++++++++++------------ 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/packages/calendaritem/calendaritem.tsx b/src/packages/calendaritem/calendaritem.tsx index cb8b7f39e3..0a1ad537ee 100644 --- a/src/packages/calendaritem/calendaritem.tsx +++ b/src/packages/calendaritem/calendaritem.tsx @@ -161,14 +161,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 || @@ -239,8 +231,8 @@ export const CalendarItem = React.forwardRef< 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) } @@ -269,19 +261,6 @@ 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 === 'single' && typeof currentDate === 'string') { @@ -409,6 +388,14 @@ export const CalendarItem = React.forwardRef< } } + 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 @@ -421,10 +408,22 @@ 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() @@ -506,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) { @@ -561,7 +554,7 @@ export const CalendarItem = React.forwardRef< } } else if ( (type === 'multiple' && isMultiple(dateStr, currentDate as string[])) || - (!Array.isArray(currentDate) && isEqual(currentDate, dateStr)) + (type === 'single' && isEqual(currentDate as string, dateStr)) ) { return activeCls } From c8478c19c645d7c304cd284c9b0027c079cdd9e4 Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Thu, 13 Feb 2025 17:29:57 +0800 Subject: [PATCH 4/5] =?UTF-8?q?perf:=20=E4=BF=AE=E8=AE=A2=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E6=96=B9=E6=B3=95=E5=90=8D=E5=92=8C=E5=BC=95=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/packages/calendar/calendar.taro.tsx | 6 +- src/packages/calendar/calendar.tsx | 6 +- src/packages/calendar/demos/h5/demo10.tsx | 29 +----- src/packages/calendar/demos/taro/demo10.tsx | 29 +----- .../calendaritem/calendaritem.taro.tsx | 48 ++++++---- src/packages/calendaritem/calendaritem.tsx | 10 +- src/utils/date.ts | 96 ++++++++----------- 7 files changed, 81 insertions(+), 143 deletions(-) diff --git a/src/packages/calendar/calendar.taro.tsx b/src/packages/calendar/calendar.taro.tsx index 1f1748c8a4..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 { getDay } 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: getDay(0), - endDate: 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 c31a06bb43..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 { getDay } 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: getDay(0), - endDate: 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/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/calendaritem/calendaritem.taro.tsx b/src/packages/calendaritem/calendaritem.taro.tsx index c760c9568e..49feda0d5a 100644 --- a/src/packages/calendaritem/calendaritem.taro.tsx +++ b/src/packages/calendaritem/calendaritem.taro.tsx @@ -5,7 +5,7 @@ import Taro, { nextTick } from '@tarojs/taro' import { PopupProps } from '@/packages/popup/index.taro' import { ComponentDefaults } from '@/utils/typings' import { - getDay, + getDateString, getCurrMonthData, getDaysStatus, getPreMonthDates, @@ -78,8 +78,8 @@ const defaultProps = { autoBackfill: false, popup: true, title: '', - startDate: getDay(0), - endDate: getDay(365), + startDate: getDateString(0), + endDate: getDateString(365), showToday: true, startText: '', endText: '', @@ -155,8 +155,8 @@ export const CalendarItem = React.forwardRef< const [scrollWithAnimation, setScrollWithAnimation] = useState(false) // 初始化开始结束数据 - const propStartDate = (startDate || getDay(0)) as string - const propEndDate = (endDate || 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) @@ -281,7 +281,7 @@ export const CalendarItem = React.forwardRef< } if (Array.isArray(currentDate) && currentDate.length) { switch (type) { - case 'range': + case 'range': { if (compareDate(currentDate[0], propStartDate)) { currentDate[0] = propStartDate } @@ -293,10 +293,9 @@ export const CalendarItem = React.forwardRef< ...splitDate(currentDate[1]), ] break - case 'multiple': - // eslint-disable-next-line no-case-declarations + } + case 'multiple': { const defaultArr = [] as string[] - // eslint-disable-next-line no-case-declarations const obj: Record = {} currentDate.forEach((item: string) => { if ( @@ -312,10 +311,9 @@ export const CalendarItem = React.forwardRef< currentDate.splice(0, currentDate.length, ...defaultArr) defaultData = [...splitDate(defaultArr[0])] break - case 'week': - // eslint-disable-next-line no-case-declarations + } + case 'week': { const [y, m, d] = splitDate(currentDate[0]) - // eslint-disable-next-line no-case-declarations const weekArr = getWeekDate(y, m, d, firstDayOfWeek) currentDate.splice(0, currentDate.length, ...weekArr) if (compareDate(currentDate[0], propStartDate)) { @@ -329,6 +327,7 @@ export const CalendarItem = React.forwardRef< ...splitDate(currentDate[1]), ] break + } default: break } @@ -372,17 +371,19 @@ export const CalendarItem = React.forwardRef< // 设置当前选中日期 const date = monthsData[current.current] switch (type) { - case 'range': + case 'range': { handleDayClick({ day: defaultData[2], type: 'active' }, date) handleDayClick( { day: defaultData[5], type: 'active' }, monthsData[current.lastCurrent] ) break - case 'week': + } + case 'week': { handleDayClick({ day: defaultData[2], type: 'curr' }, date) break - case 'multiple': + } + case 'multiple': { ;[...currentDate].forEach((item: string) => { const dateArr = splitDate(item) let currentIndex = current.current @@ -395,9 +396,11 @@ export const CalendarItem = React.forwardRef< ) }) break - default: + } + default: { handleDayClick({ day: defaultData[2], type: 'active' }, date) break + } } } @@ -587,7 +590,7 @@ export const CalendarItem = React.forwardRef< const newDate = days[3] switch (type) { - case 'multiple': + case 'multiple': { if (Array.isArray(currentDate)) { if (currentDate.length > 0) { const hasIndex = currentDate.findIndex((item) => item === newDate) @@ -606,7 +609,8 @@ export const CalendarItem = React.forwardRef< } } break - case 'range': + } + case 'range': { if (Array.isArray(currentDate)) { if (currentDate.length === 2 || currentDate.length === 0) { currentDate.splice(0, currentDate.length, newDate) @@ -620,8 +624,8 @@ export const CalendarItem = React.forwardRef< } } break - case 'week': - // eslint-disable-next-line no-case-declarations + } + case 'week': { const weekArr = getWeekDate(y, m, `${day.day}`, firstDayOfWeek) if (compareDate(weekArr[0], propStartDate)) { weekArr[0] = propStartDate @@ -635,10 +639,12 @@ export const CalendarItem = React.forwardRef< formatResultDate(weekArr[1]), ] break - default: + } + default: { setCurrentDate(newDate) state.currDateArray = [...days] break + } } if (!isFirst) { onDayClick && onDayClick(state.currDateArray) diff --git a/src/packages/calendaritem/calendaritem.tsx b/src/packages/calendaritem/calendaritem.tsx index 0a1ad537ee..d3e605cbd7 100644 --- a/src/packages/calendaritem/calendaritem.tsx +++ b/src/packages/calendaritem/calendaritem.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames' import { PopupProps } from '@/packages/popup/index' import { ComponentDefaults } from '@/utils/typings' import { - getDay, + getDateString, getCurrMonthData, getDaysStatus, getPreMonthDates, @@ -77,8 +77,8 @@ const defaultProps = { autoBackfill: false, popup: true, title: '', - startDate: getDay(0), - endDate: getDay(365), + startDate: getDateString(0), + endDate: getDateString(365), showToday: true, startText: '', endText: '', @@ -152,8 +152,8 @@ export const CalendarItem = React.forwardRef< const [monthDefaultRange, setMonthDefaultRange] = useState([]) // 初始化开始结束数据 - const propStartDate = (startDate || getDay(0)) as string - const propEndDate = (endDate || 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) diff --git a/src/utils/date.ts b/src/utils/date.ts index 47469388b9..c594246240 100644 --- a/src/utils/date.ts +++ b/src/utils/date.ts @@ -1,5 +1,9 @@ /** - * 是否为闫年 + * 判断是否为闰年 + * 规则: + * 1. 能被4整除但不能被100整除,或 + * 2. 能被400整除 + * @param {number} y - 年份 * @return {Boolse} true|false */ export const isLeapYear = (y: number): boolean => { @@ -15,8 +19,7 @@ export const getWhatDay = ( month: number, day: number ): string => { - const date = new Date(`${year}/${month}/${day}`) - const index = date.getDay() + const date = new Date(year, month - 1, day) // 月份从0开始 const dayNames = [ '星期日', '星期一', @@ -26,7 +29,7 @@ export const getWhatDay = ( '星期五', '星期六', ] - return dayNames[index] + return dayNames[date.getDay()] } /** @@ -34,12 +37,8 @@ export const getWhatDay = ( * @return {Number} */ export const getMonthPreDay = (year: number, month: number): number => { - const date = new Date(`${year}/${month}/01`) - let day = date.getDay() - if (day === 0) { - day = 7 - } - return day + const day = new Date(year, month - 1, 1).getDay() // 月份从0开始 + return day === 0 ? 7 : day // 将周日从0改为7 } /** @@ -74,16 +73,14 @@ export const getMonthDays = (year: string, month: string): number => { * @return {string} */ export const getNumTwoBit = (n: number): string => { - n = Number(n) - return (n > 9 ? '' : '0') + n + return n > 9 ? `${n}` : `0${n}` } /** * 日期对象转成字符串 * @return {string} */ -export const date2Str = (date: Date, split?: string): string => { - split = split || '-' +export const date2Str = (date: Date, split: string = '-'): string => { const y = date.getFullYear() const m = getNumTwoBit(date.getMonth() + 1) const d = getNumTwoBit(date.getDate()) @@ -95,12 +92,10 @@ export const date2Str = (date: Date, split?: string): string => { * @param {Number} 0返回今天的日期、1返回明天的日期,2返回后天得日期,依次类推 * @return {string} '2014-12-31' */ -export const 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) +export const getDateString = (offset: number = 0): string => { + const date = new Date() + date.setDate(date.getDate() + offset) + return date2Str(date, '-') } /** @@ -110,10 +105,7 @@ export const getDay = (i: number): string => { export const 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 startTime < endTime } /** @@ -123,35 +115,32 @@ export const compareDate = (date1: string, date2: string): 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() - if (startTime === endTime) { - return true - } - return false + return startTime === endTime } + export const getMonthWeek = ( - year: string, - month: string, - date: string, + year: number, + month: number, + date: number, firstDayOfWeek = 0 ): number => { - const dateNow = new Date(Number(year), parseInt(month) - 1, Number(date)) + const dateNow = new Date(year, month - 1, 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) + return Math.ceil((date + remainder) / 7) } export const getYearWeek = ( - year: string, - month: string, - date: string, + year: number, + month: number, + date: number, firstDayOfWeek = 0 ): number => { - const dateNow = new Date(Number(year), parseInt(month) - 1, Number(date)) - const dateFirst = new Date(Number(year), 0, 1) + const dateNow = new Date(year, month - 1, date) + const dateFirst = new Date(year, 0, 1) const dataNumber = Math.round( (dateNow.valueOf() - dateFirst.valueOf()) / 86400000 ) @@ -172,7 +161,6 @@ export const getWeekDate = ( 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] @@ -183,33 +171,27 @@ export const getWeekDate = ( 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] } export const formatResultDate = (date: string) => { - const days = [...date.split('-')] - days[2] = getNumTwoBit(Number(days[2])) - days[3] = `${days[0]}-${days[1]}-${days[2]}` - days[4] = getWhatDay(+days[0], +days[1], +days[2]) - return days + 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, getNumTwoBit(month), getMonthDays(String(year), String(month))] } From a20d16eb0563a847747a457aa322664bedbe275a Mon Sep 17 00:00:00 2001 From: hanyuxinting Date: Thu, 13 Feb 2025 19:37:08 +0800 Subject: [PATCH 5/5] =?UTF-8?q?test:=20=E6=8F=90=E9=AB=98=E5=8D=95?= =?UTF-8?q?=E6=B5=8B=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__snapshots__/calendar.spec.tsx.snap | 6 +- .../calendar/__tests__/calendar.spec.tsx | 199 ++++++++++++------ src/packages/calendar/demos/h5/demo3.tsx | 1 + src/packages/calendar/demos/h5/demo4.tsx | 1 + 4 files changed, 143 insertions(+), 64 deletions(-) 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/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 ( <>