从 v5 迁移到 v6
本指南介绍了将日期和时间选择器从 v5 迁移到 v6 所需的更改。
简介
首先,请查看关于 MUI X v6 发布的博文。
开始使用新版本
在 package.json
中,将日期选择器包的版本更改为 ^6.0.0
。
-"@mui/x-date-pickers": "^5.0.0",
+"@mui/x-date-pickers": "^6.0.0",
由于 v6 是一个主要版本,因此它包含影响公共 API 的更改。 这些更改是为了保持一致性、提高稳定性和为新功能腾出空间而进行的。 下面介绍了从 v5 迁移到 v6 所需的步骤。
运行代码转换 (codemod)
preset-safe
代码转换 (codemod) 将自动调整您的大部分代码,以解决 v6 中的重大更改。 您可以运行 v6.0.0/pickers/preset-safe
,仅以日期和时间选择器为目标,或运行 v6.0.0/preset-safe
,同时以数据表格为目标。
当选择 <path>
参数时,您可以对特定文件、文件夹或整个代码库运行它。
// Date and Time Pickers specific
npx @mui/x-codemod@latest v6.0.0/pickers/preset-safe <path>
// Target Data Grid as well
npx @mui/x-codemod@latest v6.0.0/preset-safe <path>
此代码转换 (codemod) 处理的重大更改在屏幕右侧的目录中用 ✅ 表情符号表示。
如果您已经应用了 v6.0.0/pickers/preset-safe
(或 v6.0.0/preset-safe
) 代码转换 (codemod),那么您应该不需要对这些项目采取任何进一步的操作。
所有其他更改都必须手动处理。
选择器组件
✅ 重命名 inputFormat
属性
在所有选择器组件上,inputFormat
属性已重命名为 format
。
<DatePicker
- inputFormat="YYYY"
+ format="YYYY"
/>
更新测试中的预期值
输入中呈现的值可能已被修改。 如果您正在使用 RTL,或者您的日期包含个位数部分,则会添加非 ASCII 字符。
如果您的测试依赖于输入值,您可以使用以下方法清除它们。
export const cleanString = (dirtyString: string) =>
dirtyString
.replace(/[\u2066\u2067\u2068\u2069]/g, '') // Remove non-ASCII characters
.replace(/ \/ /g, '/'); // Remove extra spaces
更新 value
属性的格式
以前,可以提供日期管理库能够解析的任何格式。 例如,当使用 AdapterDayjs
时,您可以传递 value={new Date()}
。 这种行为带来了很多困惑。
在 v6 中,value
属性期望的格式与任何其他保存日期的属性的格式相同。 以下是为每个适配器在当前日期初始化日期选择器的语法
// Date-fns
<DatePicker value={new Date()} />;
// Dayjs
import dayjs from 'dayjs';
<DatePicker value={dayjs()} />;
// Moment
import moment from 'moment';
<DatePicker value={moment()} />;
// Luxon
import { DateTime } from 'luxon';
<DatePicker value={DateTime.now()} />;
停止在桌面端渲染时钟
在桌面模式下,DateTimePicker
和 TimePicker
组件将不再渲染 TimeClock
组件。 TimeClock
组件已被新的 DigitalClock
组件取代。 Mobile
和 Static
变体的行为仍然相同。 如果您在桌面模式下依赖 Clock Picker 进行测试,请务必查看 测试注意事项,以选择最佳替代方案。
您可以使用新的 viewRenderers
属性手动重新启用以前的时钟组件。 以下代码在您的应用程序中的所有 DesktopTimePicker
和 DesktopDateTimePicker
上启用 TimeClock
UI。
有关更多信息,请查看通过主题文档了解默认属性。
const theme = createTheme({
components: {
MuiDesktopTimePicker: {
defaultProps: {
viewRenderers: {
hours: renderTimeViewClock,
minutes: renderTimeViewClock,
seconds: renderTimeViewClock,
},
},
},
MuiDesktopDateTimePicker: {
defaultProps: {
viewRenderers: {
hours: renderTimeViewClock,
minutes: renderTimeViewClock,
seconds: renderTimeViewClock,
},
},
},
},
});
移除键盘视图
选择器组件不再具有键盘视图,以在移动设备上的模态框内渲染输入。
如果您的日期更易于使用键盘编辑(例如:出生日期),您可以直接使用新的字段组件
function App() { return ( - <DatePicker /> + <DateField /> ) }
如果您想保留旧的键盘视图,您可以传递自定义
Layout
组件插槽以重新引入键盘视图。
✅ 重命名或重构 shouldDisableTime
属性
shouldDisableTime
属性签名已更改。 以前,它接收 value
作为小时、分钟或秒的 number
。 现在它将接收日期对象(基于使用的适配器)。 这将允许更强大的用法,并将与未来的数字时间选择视图兼容。
将属性重命名为新添加但已弃用的 shouldDisableClock
,或重构用法以考虑属性类型的更改。 代码转换 (codemod) 将负责重命名属性以保持现有功能,但您可以随意自行更新为新的 shouldDisableTime
属性。
// ℹ️ Rename and keep using the deprecated prop
// This is the change that the codemod will apply
<DateTimePicker
- shouldDisableTime={(timeValue, view) => view === 'hours' && timeValue < 12}
+ shouldDisableClock={(timeValue, view) => view === 'hours' && timeValue < 12}
/>
// ✅ Update your code to use the provided date value parameter instead of a number
<DateTimePicker
- shouldDisableTime={(timeValue, view) => view === 'hours' && timeValue < 12}
+ shouldDisableTime={(value, view) => view === 'hours' && value.hour() < 12}
/>
更改 DOM 结构
内部
CalendarOrClockPicker
组件已被移除,其所有元素都已移动到新的Layout
组件插槽。包含工具栏和视图内容的 DOM 节点(
CalendarOrClockPicker
组件的root
插槽)不再存在。 最接近的等效项现在是PickersLayout
组件的contentWrapper
插槽,它不包含工具栏。 如果您需要包含工具栏和视图内容的 DOM 节点,您将必须传递一个 自定义Layout
组件插槽。const theme = createTheme({ components: { - MuiCalendarOrClockPicker: { + MuiPickersLayout: { styleOverrides: { - root: { + contentWrapper: { backgroundColor: 'red', }, }, }, }, });
内部
PickerStaticWrapper
组件已被移除,其所有元素都已移动到新的Layout
组件插槽。const theme = createTheme({ components: { - MuiPickerStaticWrapper: { + MuiPickersLayout: { styleOverrides: { root: { opacity: 0.5, }, }, }, }, });
包含工具栏和视图内容的 DOM 节点(
PickerStaticWrapper
组件的content
插槽)不再存在。 最接近的等效项现在是PickersLayout
组件的contentWrapper
插槽,它不包含工具栏。 如果您需要包含工具栏和视图内容的 DOM 节点,您将必须传递一个 自定义Layout
组件插槽。const theme = createTheme({ components: { - MuiPickerStaticWrapper: { + MuiPickersLayout: { styleOverrides: { - content: { + contentWrapper: { opacity: 0.5, }, }, }, }, });
日期库和适配器
✅ 不要从 @date-io
导入适配器
在 v5 中,可以从 @date-io
或 @mui/x-date-pickers
导入适配器,它们是相同的。 在 v6 中,适配器由 @mui/x-date-pickers
扩展以支持 字段组件。 这意味着适配器不能再从 @date-io
导入。 它们需要从 @mui/x-date-pickers
或 @mui/x-date-pickers-pro
导入。 否则,将缺少某些方法。 如果您没有找到您正在使用的适配器,则可能是有原因的,但您可以提出 issue 以表达对此的兴趣。
-import AdapterJalaali from '@date-io/jalaali';
+import { AdapterMomentJalaali } from '@mui/x-date-pickers/AdapterMomentJalaali';
提高 Luxon 最低版本
v6 AdapterLuxon
现在需要 luxon
版本 3.0.2
或更高版本才能工作。
如果您使用的是旧版本,请查看 升级 Luxon 指南。
视图组件
✅ 重命名组件
允许选择时间、日期或日期部分而无需输入的视图组件已重命名,以更好地适应其用法
-<CalendarPicker {...props} />
+<DateCalendar {...props} />
-<DayPicker {...props} />
+<DayCalendar {...props} />
-<CalendarPickerSkeleton {...props} />
+<DayCalendarSkeleton {...props} />
-<MonthPicker {...props} />
+<MonthCalendar {...props} />
-<YearPicker {...props} />
+<YearCalendar {...props} />
-<ClockPicker {...props} />
+<TimeClock {...props} />
主题中的组件名称也已更改
-MuiCalendarPicker: {
+MuiDateCalendar: {
-MuiDayPicker: {
+MuiDayCalendar: {
-MuiCalendarPickerSkeleton: {
+MuiDayCalendarSkeleton: {
-MuiMonthPicker: {
+MuiMonthCalendar: {
-MuiYearPicker: {
+MuiYearCalendar: {
-MuiClockPicker: {
+MuiTimeClock: {
✅ 将 date
属性重命名为 value
在 MonthCalendar
、YearCalendar
、TimeClock
和 DateCalendar
(在上一节中重命名的组件)上,date
属性已重命名为 value
-<MonthPicker date={dayjs()} />
+<MonthCalendar value={dayjs()} />
-<YearPicker date={dayjs()} />
+<YearCalendar value={dayjs()} />
-<ClockPicker date={dayjs()} />
+<TimeClock value={dayjs()} />
-<CalendarPicker date={dayjs()} />
+<DateCalendar value={dayjs()} />
使用来自语言环境的 12 小时/24 小时格式作为 TimeClock
上 ampm
属性的默认值
ampm
属性的默认值从 false
更改为 utils.is12HourCycleInCurrentLocale()
。 这意味着 TimeClock
组件将为通常以 12 小时格式显示时间的语言环境使用 12 小时时间格式。
如果您想保留以前的行为,您只需将 ampm
属性设置为 false
(在上一节中重命名的组件)
- <ClockPicker />
+ <TimeClock ampm={false} />
停止在 PickersMonth
和 PickersYear
上使用响应式类
modeMobile
和 modeDesktop
类已从 PickersMonth
和 PickersYear
内部组件中移除。
如果您在响应式组件上使用这些类,您可以从 @mui/x-date-pickers
或 @mui/x-date-pickers-pro
导入 DEFAULT_DESKTOP_MODE_MEDIA_QUERY
(或者如果使用自定义媒体查询)。
<GlobalStyles
styles={{
- [`.${pickersYearClasses.modeDesktop}`]: {
- backgroundColor: 'red'
- }
+ [DEFAULT_DESKTOP_MODE_MEDIA_QUERY]: {
+ [`.${pickersYearClasses.root}`]: {
+ backgroundColor: 'red'
+ }
+ }
- [`.${pickersYearClasses.modeMobile}`]: {
- backgroundColor: 'red'
- }
+ [DEFAULT_DESKTOP_MODE_MEDIA_QUERY.replace('@media', '@media not')]: {
+ [`.${pickersYearClasses.root}`]: {
+ backgroundColor: 'red'
+ }
+ }
}}
/>
本地化
✅ 重命名本地化属性
用于设置选择器中显示的文本的属性已被 localeText
属性内的键替换
移除的属性 | 新 localText 属性中的属性 |
---|---|
endText |
end |
getClockLabelText |
clockLabelText |
getHoursClockNumberText |
hoursClockNumberText |
getMinutesClockNumberText |
minutesClockNumberText |
getSecondsClockNumberText |
secondsClockNumberText |
getViewSwitchingButtonText |
calendarViewSwitchingButtonAriaLabel |
leftArrowButtonText |
openPreviousView (或当按钮更改可见月份时为 previousMonth ) |
rightArrowButtonText |
openNextView (或当按钮更改可见月份时为 nextMonth ) |
startText |
start |
getOpenDialogAriaText |
openDatePickerDialogue /(或时间选择器的 openTimePickerDialogue ) |
例如,如果您想替换 startText
/ endText
<DateRangePicker
- startText="From"
- endText="To"
+ localeText={{
+ start: 'From',
+ end: 'To',
+ }}
/>
✅ 重命名 LocalizationProvider
上的 locale
属性
LocalizationProvider
组件的 locale
属性已重命名为 adapterLocale
<LocalizationProvider
dateAdapter={AdapterDayjs}
- locale="fr"
+ adapterLocale="fr"
>
{children}
</LocalizationProvider
组件插槽 / 组件插槽属性
用于将属性传递到 UI 部分(例如:将属性传递到输入)的所有属性都已被组件插槽属性替换。 用于覆盖 UI 部分(例如:传递自定义日期渲染器)的所有属性都已被组件插槽替换。
您可以在 Base UI 文档中找到有关此模式的更多信息。
这些更改适用于所有具有该属性的组件。 例如,ToolbarComponent
已被所有选择器上的 Toolbar
组件插槽替换。
输入渲染器(v5 中必需)
renderInput
已被input
组件插槽属性替换<DatePicker - renderInput={(inputProps) => <TextField {...props} variant="outlined" />} + slotProps={{ textField: { variant: 'outlined' } }} /> <DateRangePicker - renderInput={(startProps, endProps) => ( - <React.Fragment> - <TextField {...startProps} variant="outlined" /> - <Box sx={{ mx: 2 }}> - </Box> - <TextField {...endProps} variant="outlined" /> - </React.Fragment> - )} + slotProps={{ textField: { variant: 'outlined' } }} />
日期范围选择器还具有新的
fieldSeparator
组件插槽和组件插槽属性,仅用于自定义 UI 的这一部分<DateRangePicker - renderInput={(startProps, endProps) => ( - <React.Fragment> - <TextField {...startProps} /> - <Box sx={{ mx: 2 }}> to </Box> - <TextField {...endProps} /> - </React.Fragment> - )} + slotProps={{ fieldSeparator: { children: 'to' } }} />
工具栏 (ToolbarComponent
)
✅
ToolbarComponent
已被toolbar
组件插槽替换<DatePicker - ToolbarComponent={MyToolbar} + slots={{ toolbar: MyToolbar }} />
✅
toolbarPlaceholder
、toolbarFormat
和showToolbar
属性已移动到toolbar
组件插槽属性<DatePicker - toolbarPlaceholder="__" - toolbarFormat="DD / MM / YYYY" - showToolbar + slotProps={{ + toolbar: { + toolbarPlaceholder: '__', + toolbarFormat: 'DD / MM / YYYY', + hidden: false, + } + }} />
✅
toolbarTitle
属性已移动到本地化对象<DatePicker - toolbarTitle="Title" + localeText={{ toolbarTitle: 'Title' }} />
✅ 工具栏相关的翻译键已重命名,以更好地适应其用法
<LocalizationProvider localeText={{ - datePickerDefaultToolbarTitle: 'Date Picker', + datePickerToolbarTitle: 'Date Picker', - timePickerDefaultToolbarTitle: 'Time Picker', + timePickerToolbarTitle: 'Time Picker', - dateTimePickerDefaultToolbarTitle: 'Date Time Picker', + dateTimePickerToolbarTitle: 'Date Time Picker', - dateRangePickerDefaultToolbarTitle: 'Date Range Picker', + dateRangePickerToolbarTitle: 'Date Range Picker', }} />
工具栏上的
onChange
/openView
属性已重命名为onViewChange
/view
。const CustomToolbarComponent = props => ( <div> - <button onChange={() => props.onChange('day')}>Show day view</button> + <button onClick={() => props.onViewChange('day')}>Show day view</button> - <div>Current view: {props.openView}</div> + <div>Current view: {props.view}</div> </div> ) <DatePicker - ToolbarComponent={CustomToolbarComponent} + slots={{ + toolbar: CustomToolbarComponent + }} />
日期范围选择器工具栏上的
currentlySelectingRangeEnd
/setCurrentlySelectingRangeEnd
属性已重命名为rangePosition
/onRangePositionChange
。const CustomToolbarComponent = props => ( <div> - <button onChange={() => props.setCurrentlySelectingRangeEnd('end')}>Edit end date</button> + <button onClick={() => props.onRangePositionChange('end')}>Edit end date</button> - <div>Is editing end date: {props.currentlySelectingRangeEnd === 'end'}</div> + <div>Is editing end date: {props.rangePosition === 'end'}</div> </div> ) <DateRangePicker - ToolbarComponent={CustomToolbarComponent} + slots={{ + toolbar: CustomToolbarComponent + }} />
标签页
✅
hideTabs
和timeIcon
属性已移动到tabs
组件插槽属性。dateRangeIcon
属性已重命名为dateIcon
并移动到tabs
组件插槽属性<DateTimePicker - hideTabs={false} - dateRangeIcon={<LightModeIcon />} - timeIcon={<AcUnitIcon />} + slotProps={{ + tabs: { + hidden: false, + dateIcon: <LightModeIcon />, + timeIcon: <AcUnitIcon />, + } + }} />
DateTimePickerTabs
组件上的onChange
属性已重命名为onViewChange
,以更好地适应其用法<DateTimePickerTabs - onChange={() => {}} + onViewChange={() => {}} />
const CustomTabsComponent = props => ( <div> - <button onClick={() => props.onChange('day')}>Show day view</button> + <button onClick={() => props.onViewChange('day')}>Show day view</button> </div> ) <DateTimePicker slots={{ tabs: CustomTabsComponent }} />
操作栏
actionBar
组件插槽的actions
属性不再能接收回调。 相反,您可以在组件插槽属性级别传递回调<DatePicker - componentsProps={{ - actionBar: { - actions: (variant) => (variant === 'desktop' ? [] : ['clear']), - }, - }} + componentsProps={{ + actionBar: ({ wrapperVariant }) => ({ + actions: wrapperVariant === 'desktop' ? [] : ['clear'], + }), + }} // or using the new `slots` prop + slotProps={{ + actionBar: ({ wrapperVariant }) => ({ + actions: wrapperVariant === 'desktop' ? [] : ['clear'], + }), + }} />
日期 (renderDay
)
renderDay
属性已由day
组件插槽替换<DatePicker - renderDay={(_, dayProps) => <CustomDay {...dayProps} />} + slots={{ day: CustomDay }} />
Day
组件插槽不再接收selectedDays
属性。 如果您需要访问它,您可以控制值并将其传递给组件插槽属性function CustomDay({ selectedDay, ...other }) { // do something with 'selectedDay' return <PickersDay {...other} />; } function App() { const [value, setValue] = React.useState(null); return ( <DatePicker value={value} onChange={(newValue) => setValue(newValue)} slots={{ day: CustomDay }} slotProps={{ day: { selectedDay: value }, }} /> ); }
✅ Popper (PopperProps
)
PopperProps
属性已由popper
组件插槽属性替换<DatePicker - PopperProps={{ onClick: handleClick }} + slotProps={{ popper: { onClick: handleClick } }} />
✅ 桌面端过渡效果 (TransitionComponent
)
TransitionComponent
属性已由desktopTransition
组件插槽替换<DatePicker - TransitionComponent={Fade} + slots={{ desktopTransition: Fade }} />
✅ 对话框 (DialogProps
)
DialogProps
属性已由dialog
组件插槽属性替换<DatePicker - DialogProps={{ backgroundColor: 'red' }} + slotProps={{ dialog: { backgroundColor: 'red' }}} />
✅ 桌面端纸张 (PaperProps
)
PaperProps
属性已由desktopPaper
组件插槽属性替换<DatePicker - PaperProps={{ backgroundColor: 'red' }} + slotProps={{ desktopPaper: { backgroundColor: 'red' } }} />
✅ 桌面端 TrapFocus (TrapFocusProp
)
TrapFocusProps
属性已由desktopTrapFocus
组件插槽属性替换<DatePicker - TrapFocusProps={{ isEnabled: () => false }} + slotProps={{ desktopTrapFocus: { isEnabled: () => false } }} />
纸张内容
PaperContent
/paperContent
组件插槽和组件插槽属性已被移除。您可以使用新的
Layout
组件插槽。 主要区别在于您现在接收 UI 的各个部分,而不是单个children
属性+import { usePickerLayout } from '@mui/x-date-pickers/PickersLayout'; function MyCustomLayout(props) { - const { children } = props; - - return ( - <React.Fragment> - {children} - <div>Custom component</div> - </React.Fragment> - ); + const { toolbar, tabs, content, actionBar} = usePickerLayout(props); + + return ( + <PickersLayoutRoot> + {toolbar} + {content} + {actionBar} + <div>Custom component</div> + </PickersLayoutRoot> + ); } function App() { return ( <DatePicker - components={{ - PaperContent: MyCustomLayout, - }} + components={{ + Layout: MyCustomLayout, + }} // or using the new `slots` prop + slots={{ + layout: MyCustomLayout, + }} /> ); }
✅ 左箭头按钮
组件插槽
LeftArrowButton
已重命名为PreviousIconButton
<DatePicker - components={{ - LeftArrowButton: CustomButton, - }} + components={{ + PreviousIconButton: CustomButton, + }} // or using the new `slots` prop + slots={{ + previousIconButton: CustomButton, + }} - componentsProps={{ - leftArrowButton: {}, - }} + componentsProps={{ + previousIconButton: {}, + }} // or using the new `slotProps` prop + slotProps={{ + previousIconButton: {}, + }} />
✅ 右箭头按钮
组件插槽
RightArrowButton
已重命名为NextIconButton
<DatePicker - components={{ - RightArrowButton: CustomButton, - }} + components={{ + NextIconButton: CustomButton, + }} // or using the new `slots` prop + slots={{ + nextIconButton: CustomButton, + }} - componentsProps={{ - rightArrowButton: {}, - }} + componentsProps={{ + nextIconButton: {}, + }} // or using the new `slotProps` prop + slotProps={{ + nextIconButton: {}, + }} />
✅ 输入框
InputProps
属性已被移除。 您可以使用textField
组件插槽属性的InputProps
<DatePicker - InputProps={{ color: 'primary' }} + slotProps={{ textField: { InputProps: { color: 'primary' } } }} />
✅ 输入装饰
InputAdornmentProps
属性已由inputAdornment
组件插槽属性替换<DatePicker - InputAdornmentProps={{ position: 'start' }} + slotProps={{ inputAdornment: { position: 'start' } }} />
✅ 打开选择器按钮
OpenPickerButtonProps
属性已由openPickerButton
组件插槽属性替换<DatePicker - OpenPickerButtonProps={{ ref: buttonRef }} + slotProps={{ openPickerButton: { ref: buttonRef } }} />
重命名剩余的 private
组件
前缀为 Private
的四个组件现在是稳定的。 这些组件已重命名
PrivatePickersMonth
->MuiPickersMonth
PrivatePickersSlideTransition
->MuiPickersSlideTransition
PrivatePickersToolbarText
->MuiPickersToolbarText
PrivatePickersYear
->MuiPickersYear
手动样式覆盖将需要使用更新的类
-.PrivatePickersMonth-root {
+.MuiPickersMonth-root {
-.PrivatePickersSlideTransition-root {
+.MuiPickersSlideTransition-root {
-.PrivatePickersToolbarText-root {
+.MuiPickersToolbarText-root {
-.PrivatePickersYear-root {
+.MuiPickersYear-root {
组件名称更改也反映在 themeAugmentation
中
const theme = createTheme({
components: {
- PrivatePickersMonth: {
+ MuiPickersMonth: {
// overrides
},
- PrivatePickersSlideTransition: {
+ MuiPickersSlideTransition: {
// overrides
},
- PrivatePickersToolbarText: {
+ MuiPickersToolbarText: {
// overrides
},
- PrivatePickersYear: {
+ MuiPickersYear: {
// overrides
},
},
});
字段 onChange
属性的行为
由于屏蔽输入已被 字段 替换,因此输入值在大多数情况下都是有效的。
在 v5 中,用户必须删除一个字符并键入另一个字符才能更新日期,从而导致 onChange
被调用两次。 首先是删除的字符,然后再次是完整的日期。
在 v6 中,用户可以覆盖字段部分,因此几乎每次按键都会调用 onChange
。
如果您依赖 onChange
发送服务器请求,您可能对去抖动 (debouncing) 它以避免发送过多请求感兴趣。 为此,请参阅相应的 文档示例。
将 components
重命名为 slots
(可选)
components
和 componentsProps
属性正在分别重命名为 slots
和 slotProps
属性。 这是 MUI 维护的所有不同库之间缓慢而持续的努力。 为了平稳过渡,选择器同时支持已弃用的 components
属性和新的 slots
属性。
如果您想使用新的 API 并且不想看到已弃用属性的使用,请考虑运行 rename-components-to-slots
代码转换 (codemod) 来处理属性重命名。
npx @mui/x-codemod@latest v6.0.0/pickers/rename-components-to-slots <path>
有关更多信息,请查看 RFC。