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

如何实现仅选择年月的MUI X DateRangePicker自定义组件

基于MUI实现仅年月选择的DateRangePicker(单输入框+自定义弹出层)

核心实现思路

要实现仅支持年月选择的单输入框DateRangePicker,需通过MUI插槽(slots)自定义日历视图,调整弹出层(Popper)定位逻辑解决超出屏幕问题,最后合并输入框为单个统一显示。

完整代码示例

import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DateRangePicker } from '@mui/x-date-pickers-pro/DateRangePicker';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import TextField from '@mui/material/TextField';
import dayjs from 'dayjs';

// 自定义仅支持年月选择的日历组件
const YearMonthCalendar = ({ ...props }) => {
  return (
    <DateCalendar
      {...props}
      views={['year', 'month']}
      slotProps={{
        toolbar: { hidden: false },
        month: { disableMonthSwitching: false },
      }}
    />
  );
};

const YearMonthRangePicker = () => {
  return (
    <LocalizationProvider dateAdapter={AdapterDayjs}>
      <DateRangePicker
        // 替换默认日历为自定义年月视图
        slots={{ calendar: YearMonthCalendar }}
        // 配置弹出层避免超出屏幕
        slotProps={{
          popper: {
            placement: 'bottom-start',
            modifiers: [
              {
                name: 'preventOverflow',
                options: {
                  padding: 16, // 与屏幕边缘保持16px间距
                  altAxis: true, // 同时处理水平/垂直方向溢出
                },
              },
              {
                name: 'flip',
                options: {
                  fallbackPlacements: ['top-start'], // 底部空间不足时自动切换到顶部
                },
              },
            ],
            // 若仍有溢出问题,可禁用portal让弹出层在父元素内渲染
            // disablePortal: true
          },
        }}
        // 自定义单输入框渲染逻辑
        renderInput={(startProps, endProps) => {
          const [startDate, endDate] = startProps.value || [];
          const displayValue = startDate && endDate
            ? `${dayjs(startDate).format('YYYY-MM')} 至 ${dayjs(endDate).format('YYYY-MM')}`
            : '';

          return (
            <TextField
              {...startProps}
              value={displayValue}
              placeholder="选择年月范围"
              InputProps={{ readOnly: true }}
            />
          );
        }}
      />
    </LocalizationProvider>
  );
};

export default YearMonthRangePicker;

关键问题解决

  1. 日历超出屏幕

    • 利用Popper的preventOverflow修饰符设置屏幕边缘间距,避免弹出层贴边或超出。
    • 配置flip修饰符,当底部空间不足时自动切换到顶部显示。
    • 若问题仍存在,开启disablePortal: true,让弹出层在父组件DOM层级内渲染(需确保父元素有足够空间且未设置overflow: hidden)。
  2. 单输入框显示

    • 通过renderInput合并两个默认输入框为单个,根据选中的日期范围格式化显示文本。
    • 设置输入框为只读,避免用户手动输入不符合格式的内容。
  3. 仅年月选择限制

    • 自定义YearMonthCalendar组件,通过views={['year', 'month']}限制日历仅显示年、月视图,屏蔽日选择逻辑。

样式优化(可选)

若日历宽度过宽,可通过CSS限制:

.MuiDateCalendar-root {
  max-width: 320px;
}

内容的提问来源于stack exchange,提问作者Ana Gomes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 16:27:37