You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为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对应的函数,具体步骤如下:

  1. 导入所需的date-fns函数
    从date-fns中导入需要的工具函数:
import { addMonths, addYears, subMonths, subYears, format } from 'date-fns';
  1. 替换日期操作方法
    将原代码中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)
  1. 确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:47:31