React MUI X Date Picker界面自定义及年份限制问题求助
React + Material UI Date Picker 问题解决
问题说明
- 调整Date Picker操作按钮(确认、清除、取消、今日)的显示位置
- 限制年份选择范围,避免展示完整年份滚轮;使用
requireInput时出现错误,需替代方案
原始代码
import React from 'react'; import Rating from '@mui/material/Rating'; import './MyMUIStyles.scss'; import { Dayjs } from 'dayjs'; import dayjs from 'dayjs'; import Box from '@mui/material/Box'; import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import ListItemButton from '@mui/material/ListItemButton'; import ListItemText from '@mui/material/ListItemText'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { StaticDatePicker } from '@mui/x-date-pickers/StaticDatePicker'; import { PickersActionBarProps } from '@mui/x-date-pickers/PickersActionBar'; import RestaurantIcon from '@mui/icons-material/Restaurant'; import { PickersLayoutProps, usePickerLayout, pickersLayoutClasses, PickersLayoutRoot, PickersLayoutContentWrapper, } from '@mui/x-date-pickers/PickersLayout'; import { DateView } from '@mui/x-date-pickers/models'; import { YearPicker } from '@mui/x-date-pickers/YearPicker'; function ActionList(props: PickersActionBarProps) { const { onAccept, onClear, onCancel, onSetToday } = props; const actions = [ { text: 'Accept', method: onAccept }, { text: 'Clear', method: onClear }, { text: 'Cancel', method: onCancel }, { text: 'Today', method: onSetToday }, ]; return ( <List> {actions.map(({ text, method }) => ( <ListItem key={text} disablePadding> <ListItemButton onClick={method}> <ListItemText primary={text} /> </ListItemButton> </ListItem> ))} </List> ); } function RestaurantHeader() { return ( <Box sx={{ gridColumn: 1, gridRow: 1, display: 'flex', justifyContent: 'center', alignItems: 'center', }} > <RestaurantIcon /> </Box> ); } function CustomLayout(props: PickersLayoutProps<Dayjs | null, Dayjs, DateView>) { const { toolbar, tabs, content, actionBar } = usePickerLayout(props); return ( <PickersLayoutRoot ownerState={props} sx={{ overflow: 'auto', [`.${pickersLayoutClasses.actionBar}`]: { gridColumn: 1, gridRow: 2, }, [`.${pickersLayoutClasses.toolbar}`]: { gridColumn: 2, gridRow: 1, }, }} > <RestaurantHeader /> {toolbar} {actionBar} <PickersLayoutContentWrapper className={pickersLayoutClasses.contentWrapper}> {tabs} {content} </PickersLayoutContentWrapper> </PickersLayoutRoot> ); } function MyAllMUITest() { const [value, setValue] = React.useState<Dayjs | null>(null); return ( <div> <LocalizationProvider dateAdapter={AdapterDayjs}> <DatePicker value={value} onChange={(newValue) => setValue(newValue)} slots={{ layout: CustomLayout, actionBar: ActionList, }} /> </LocalizationProvider> <Rating className="rating-box" defaultValue={2} icon={ <img src="/assets/images/icon/Star-Filled.png" alt="filled star" /> } emptyIcon={ <img src="/assets/images/icon/Star-Outline.png" alt="empty star" /> } /> </div> ); } export default MyAllMUITest;
解决方案
1. 迁移操作按钮位置
弹窗内调整位置
你已通过slots.layout自定义布局,只需修改CustomLayout中PickersLayoutRoot的sx配置,调整actionBar的Grid属性即可改变位置:
- 比如将按钮移到弹窗底部,占满所有列:
[`.${pickersLayoutClasses.actionBar}`]: { gridColumn: 1 / -1, gridRow: 3, display: 'flex', justifyContent: 'flex-end', gap: 1 }
完全移出弹窗到页面其他位置
如果要把按钮放到Date Picker弹窗外部,可通过父组件状态控制:
function MyAllMUITest() { const [value, setValue] = React.useState<Dayjs | null>(null); const [open, setOpen] = React.useState(false); return ( <div> <LocalizationProvider dateAdapter={AdapterDayjs}> <DatePicker value={value} onChange={(newValue) => setValue(newValue)} open={open} onOpen={() => setOpen(true)} onClose={() => setOpen(false)} slots={{ layout: CustomLayout }} slotProps={{ actionBar: { hidden: true } }} // 隐藏默认弹窗内按钮 /> </LocalizationProvider> {/* 外部操作按钮 */} <Box sx={{ mt: 2, gap: 1, display: 'flex' }}> <button onClick={() => setOpen(true)}>打开选择器</button> <button onClick={() => {setValue(dayjs()); setOpen(false);}}>设置今日</button> <button onClick={() => {setValue(null); setOpen(false);}}>清除</button> <button onClick={() => setOpen(false)}>取消</button> </Box> <Rating className="rating-box" defaultValue={2} ... /> </div> ); }
2. 限制年份范围
方法1:minDate + maxDate(推荐)
直接通过DatePicker的minDate和maxDate属性设置允许的日期区间,年份滚轮会自动过滤超出范围的选项:
minDate={dayjs('2010-01-01')} maxDate={dayjs('2025-12-31')}
方法2:自定义yearPicker插槽
如果需要指定固定年份列表,而非连续区间,可自定义年份选择器:
const CustomYearPicker = (props) => { const allowedYears = [2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025]; return ( <YearPicker {...props} years={allowedYears.map(year => dayjs(`${year}-01-01`))} /> ); }; // 在DatePicker的slots中添加 slots={{ yearPicker: CustomYearPicker }}
内容的提问来源于stack exchange,提问作者Aleng
相关产品推荐
相关产品推荐

