为MUI Date Picker自定义日历头时如何替换dayjs为date-fns
问题
我正尝试为MUI Date Picker组件添加自定义日历头,但将默认的dayjs类型切换为date-fns时遇到了问题。以下是我的Date Picker组件和自定义头组件代码:
Date Picker组件代码
<StyledDatePicker open={open} value={date} onChange={(newValue) => onChange(newValue as Date)} slots={{ openPickerIcon: CalendarIcon, shortcuts: CustomRangeShortcuts as any, calendarHeader: CustomCalendarHeader, }} slotProps={{ actionBar: { actions: ['today'], }, shortcuts: { items: MUI_DATE_PICKER_SHORTCUTS, }, openPickerButton: { onClick: iconButtonOnClick, }, textField: { variant: 'filled', onFocus: inputFocused, onBlur: close }, }} />
自定义日历头组件代码
const CustomCalendarHeader = (props: PickersCalendarHeaderProps<Date>) => { const { currentMonth, onMonthChange } = props; const selectNextMonth = () => onMonthChange(currentMonth.add(1, 'month'), 'left'); const selectNextYear = () => onMonthChange(currentMonth.add(1, 'year'), 'left'); const selectPreviousMonth = () => onMonthChange(currentMonth.subtract(1, 'month'), 'right'); const selectPreviousYear = () => onMonthChange(currentMonth.subtract(1, 'year'), 'right'); return ( <CustomCalendarHeaderRoot> <Stack spacing={1} direction="row"> <IconButton onClick={selectPreviousYear} title="Previous year"> <KeyboardDoubleArrowLeftIcon /> </IconButton> <IconButton onClick={selectPreviousMonth} title="Previous month"> <ChevronLeft /> </IconButton> </Stack> <Typography variant="body2">{currentMonth.format('MMMM YYYY')}</Typography> <Stack spacing={1} direction="row"> <IconButton onClick={selectNextMonth} title="Next month"> <ChevronRight /> </IconButton> <IconButton onClick={selectNextYear} title="Next year"> <KeyboardDoubleArrowRightIcon /> </IconButton> </Stack> </CustomCalendarHeaderRoot> ); }
示例中的自定义头属性类型使用的是Dayjs(PickersCalendarHeaderProps<Dayjs>),我想要使用date-fns,请问如何基于date-fns实现此功能?
解决方案
date-fns是纯函数式日期库,没有dayjs那样的实例方法,需要替换所有日期操作逻辑为date-fns对应的函数,具体步骤如下:
- 导入所需的date-fns函数
从date-fns中导入需要的工具函数:
import { addMonths, addYears, subMonths, subYears, format } from 'date-fns';
- 替换日期操作方法
将原代码中dayjs的实例方法替换为date-fns的纯函数:
currentMonth.add(1, 'month')→addMonths(currentMonth, 1)currentMonth.add(1, 'year')→addYears(currentMonth, 1)currentMonth.subtract(1, 'month')→subMonths(currentMonth, 1)currentMonth.subtract(1, 'year')→subYears(currentMonth, 1)currentMonth.format('MMMM YYYY')→format(currentMonth, 'MMMM yyyy')(注意date-fns中四位年份用小写yyyy)
- 确保MUI Date Picker配置date-fns适配器
项目中必须通过LocalizationProvider配置使用DateFnsAdapter,否则组件无法正确处理date-fns逻辑:
import { LocalizationProvider } from '@mui/x-date-pickers'; import { DateFnsAdapter } from '@mui/x-date-pickers/DateFnsAdapter'; // 在根组件或DatePicker父组件中包裹 <LocalizationProvider dateAdapter={DateFnsAdapter}> <StyledDatePicker {/* 你的组件属性 */} /> </LocalizationProvider>
修改后的完整CustomCalendarHeader代码
import { addMonths, addYears, subMonths, subYears, format } from 'date-fns'; import { PickersCalendarHeaderProps } from '@mui/x-date-pickers'; import { Stack, IconButton, Typography } from '@mui/material'; import { KeyboardDoubleArrowLeftIcon, ChevronLeft, ChevronRight, KeyboardDoubleArrowRightIcon } from '@mui/icons-material'; const CustomCalendarHeader = (props: PickersCalendarHeaderProps<Date>) => { const { currentMonth, onMonthChange } = props; const selectNextMonth = () => onMonthChange(addMonths(currentMonth, 1), 'left'); const selectNextYear = () => onMonthChange(addYears(currentMonth, 1), 'left'); const selectPreviousMonth = () => onMonthChange(subMonths(currentMonth, 1), 'right'); const selectPreviousYear = () => onMonthChange(subYears(currentMonth, 1), 'right'); return ( <CustomCalendarHeaderRoot> <Stack spacing={1} direction="row"> <IconButton onClick={selectPreviousYear} title="Previous year"> <KeyboardDoubleArrowLeftIcon /> </IconButton> <IconButton onClick={selectPreviousMonth} title="Previous month"> <ChevronLeft /> </IconButton> </Stack> <Typography variant="body2">{format(currentMonth, 'MMMM yyyy')}</Typography> <Stack spacing={1} direction="row"> <IconButton onClick={selectNextMonth} title="Next month"> <ChevronRight /> </IconButton> <IconButton onClick={selectNextYear} title="Next year"> <KeyboardDoubleArrowRightIcon /> </IconButton> </Stack> </CustomCalendarHeaderRoot> ); };
内容的提问来源于stack exchange,提问作者Dov Royal
相关产品推荐
相关产品推荐

