從 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 所需的步驟。
執行程式碼修改 (codemods)
preset-safe
程式碼修改將自動調整您的大部分程式碼,以應對 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>
此程式碼修改處理的重大變更在螢幕右側的目錄中以 ✅ 表情符號標示。
如果您已套用 v6.0.0/pickers/preset-safe
(或 v6.0.0/preset-safe
) 程式碼修改,則您應該不需要對這些項目採取任何進一步的動作。
所有其他變更都必須手動處理。
選擇器元件
✅ 重新命名 inputFormat
prop
inputFormat
prop 已在所有選擇器元件上重新命名為 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
prop 的格式
先前,您可以提供日期管理函式庫能夠剖析的任何格式。例如,當使用 AdapterDayjs
時,您可以傳遞 value={new Date()}
。這種行為造成了很多混淆。
在 v6 中,value
prop 預期的格式與任何其他持有日期的 prop 相同。以下是在每個 adapter 中將日期選擇器初始化為目前日期的語法
// 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
prop 手動重新啟用先前的時鐘元件。以下程式碼在您應用程式中的所有 DesktopTimePicker
和 DesktopDateTimePicker
上啟用 TimeClock
UI。
請查看透過主題文件設定預設 props 以取得更多資訊。
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
元件 slot 以重新引入鍵盤檢視。
✅ 重新命名或重構 shouldDisableTime
prop
shouldDisableTime
prop 簽章已變更。先前它接收 value
作為小時、分鐘或秒的 number
。現在它將接收日期物件 (基於使用的 adapter)。這將允許更強大的使用方式,並與未來的數位時間選擇檢視相容。
將 prop 重新命名為新增加但已棄用的 shouldDisableClock
,或重構用法以考慮 prop 類型的變更。程式碼修改將負責重新命名 prop 以保持現有功能,但您可以隨時自行更新為新的 shouldDisableTime
prop。
// ℹ️ 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
元件 slot。包含工具列和檢視內容 (
CalendarOrClockPicker
元件的root
slot) 的 DOM 節點不再存在。最接近的等效項現在是PickersLayout
元件的contentWrapper
slot,它不包含工具列。如果您需要包含工具列和檢視內容的 DOM 節點,您將必須傳遞自訂Layout
元件 slot。const theme = createTheme({ components: { - MuiCalendarOrClockPicker: { + MuiPickersLayout: { styleOverrides: { - root: { + contentWrapper: { backgroundColor: 'red', }, }, }, }, });
內部
PickerStaticWrapper
元件已移除,其所有元素都已移至新的Layout
元件 slot。const theme = createTheme({ components: { - MuiPickerStaticWrapper: { + MuiPickersLayout: { styleOverrides: { root: { opacity: 0.5, }, }, }, }, });
包含工具列和檢視內容 (
PickerStaticWrapper
元件的content
slot) 的 DOM 節點不再存在。最接近的等效項現在是PickersLayout
元件的contentWrapper
slot,它不包含工具列。如果您需要包含工具列和檢視內容的 DOM 節點,您將必須傳遞自訂Layout
元件 slot。const theme = createTheme({ components: { - MuiPickerStaticWrapper: { + MuiPickersLayout: { styleOverrides: { - content: { + contentWrapper: { opacity: 0.5, }, }, }, }, });
日期函式庫和 adapters
✅ 不要從 @date-io
匯入 adapter
在 v5 中,可以從 @date-io
或 @mui/x-date-pickers
匯入 adapters,它們是相同的。在 v6 中,adapters 由 @mui/x-date-pickers
擴展以支援欄位元件。這表示無法再從 @date-io
匯入 adapters。它們需要從 @mui/x-date-pickers
或 @mui/x-date-pickers-pro
匯入。否則,某些方法將會遺失。如果您找不到您正在使用的 adapter,可能是有原因的,但您可以提出 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
prop 重新命名為 value
date
prop 已在 MonthCalendar
、YearCalendar
、TimeClock
和 DateCalendar
(先前章節中重新命名的元件) 上重新命名為 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()} />
從 locale 使用 12 小時/24 小時格式作為 TimeClock
上 ampm
prop 的預設值
ampm
prop 的預設值已從 false
變更為 utils.is12HourCycleInCurrentLocale()
。這表示 TimeClock
元件將針對時間通常以 12 小時格式顯示的 locale 使用 12 小時時間格式。
如果您想保留先前的行為,您只需將 ampm
prop 設定為 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'
+ }
+ }
}}
/>
本地化
✅ 重新命名本地化 props
用於設定選擇器中顯示文字的 props 已替換為 localeText
prop 內的鍵
已移除 prop | 新 localText prop 中的屬性 |
---|---|
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
prop
LocalizationProvider
元件的 locale
prop 已重新命名為 adapterLocale
<LocalizationProvider
dateAdapter={AdapterDayjs}
- locale="fr"
+ adapterLocale="fr"
>
{children}
</LocalizationProvider
元件 slots / 元件 slot props
所有用於將 props 傳遞到 UI 部分 (例如:將 prop 傳遞到輸入) 的 props 已被元件 slot props 取代。所有用於覆寫 UI 部分 (例如:傳遞自訂日期呈現器) 的 props 已被元件 slots 取代。
您可以在Base UI 文件中找到有關此模式的更多資訊。
這些變更適用於所有具有 prop 的元件。例如,ToolbarComponent
已被所有選擇器上的 Toolbar
元件 slot 取代。
輸入呈現器 (v5 中為必要)
renderInput
已被input
元件 slot props 取代<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
元件 slot 和元件 slot props,僅用於自訂 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
元件 slot 取代<DatePicker - ToolbarComponent={MyToolbar} + slots={{ toolbar: MyToolbar }} />
✅
toolbarPlaceholder
、toolbarFormat
和showToolbar
props 已移至toolbar
元件 slot props<DatePicker - toolbarPlaceholder="__" - toolbarFormat="DD / MM / YYYY" - showToolbar + slotProps={{ + toolbar: { + toolbarPlaceholder: '__', + toolbarFormat: 'DD / MM / YYYY', + hidden: false, + } + }} />
✅
toolbarTitle
prop 已移至本地化物件<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
props 已重新命名為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
props 已重新命名為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
props 已移至tabs
元件 slot props。dateRangeIcon
prop 已重新命名為dateIcon
並移至tabs
元件 slot props<DateTimePicker - hideTabs={false} - dateRangeIcon={<LightModeIcon />} - timeIcon={<AcUnitIcon />} + slotProps={{ + tabs: { + hidden: false, + dateIcon: <LightModeIcon />, + timeIcon: <AcUnitIcon />, + } + }} />
DateTimePickerTabs
元件上的onChange
prop 已重新命名為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
元件 slot 的actions
prop 無法再接收回呼。相反地,您可以在元件 slot props 層級傳遞回呼<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
prop 已被day
元件 slot 取代<DatePicker - renderDay={(_, dayProps) => <CustomDay {...dayProps} />} + slots={{ day: CustomDay }} />
Day
元件 slot 不再接收selectedDays
prop。如果您需要存取它,您可以控制值並將其傳遞到元件 slot propsfunction 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
prop 已被popper
元件 slot props 取代<DatePicker - PopperProps={{ onClick: handleClick }} + slotProps={{ popper: { onClick: handleClick } }} />
✅ 桌面轉場效果 (TransitionComponent
)
TransitionComponent
prop 已被desktopTransition
元件 slot 取代<DatePicker - TransitionComponent={Fade} + slots={{ desktopTransition: Fade }} />
✅ 對話框 (DialogProps
)
DialogProps
prop 已被dialog
元件 slot props 取代<DatePicker - DialogProps={{ backgroundColor: 'red' }} + slotProps={{ dialog: { backgroundColor: 'red' }}} />
✅ 桌面紙張 (PaperProps
)
PaperProps
prop 已被desktopPaper
元件 slot props 取代<DatePicker - PaperProps={{ backgroundColor: 'red' }} + slotProps={{ desktopPaper: { backgroundColor: 'red' } }} />
✅ 桌面 TrapFocus (TrapFocusProp
)
TrapFocusProps
prop 已被desktopTrapFocus
元件 slot props 取代<DatePicker - TrapFocusProps={{ isEnabled: () => false }} + slotProps={{ desktopTrapFocus: { isEnabled: () => false } }} />
紙張內容
PaperContent
/paperContent
元件 slot 和元件 slot props 已移除。您可以使用新的
Layout
元件 slot。主要差異在於您現在接收 UI 的各個部分,而不是單個children
prop+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, + }} /> ); }
✅ 左箭頭按鈕
元件 slot
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: {}, + }} />
✅ 右箭頭按鈕
元件 slot
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
prop 已移除。您可以使用textField
元件 slot props 的InputProps
<DatePicker - InputProps={{ color: 'primary' }} + slotProps={{ textField: { InputProps: { color: 'primary' } } }} />
✅ 輸入裝飾
InputAdornmentProps
prop 已被inputAdornment
元件 slot props 取代<DatePicker - InputAdornmentProps={{ position: 'start' }} + slotProps={{ inputAdornment: { position: 'start' } }} />
✅ 開啟選擇器按鈕
OpenPickerButtonProps
prop 已被openPickerButton
元件 slot props 取代<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
props 的行為
由於遮罩輸入已被欄位取代,因此輸入值在大多數情況下都是有效的。
在 v5 中,使用者必須刪除一個字元並輸入另一個字元才能更新日期,導致 onChange
被呼叫兩次。首先是已刪除的字元,然後是完整的日期。
在 v6 中,使用者可以覆寫欄位區段,因此幾乎每次按下按鍵都會呼叫 onChange
。
如果您依賴 onChange
發送伺服器請求,您可能會對延遲它以避免發送過多請求感興趣。若要執行此操作,請參閱相應的文件範例。
將 components
重新命名為 slots
(選用)
components
和 componentsProps
props 正在分別重新命名為 slots
和 slotProps
props。這是 MUI 維護的所有不同函式庫之間緩慢且持續進行的工作。為了使過渡更順暢,選擇器同時支援已棄用的 components
props 和新的 slots
props。
如果您想使用新的 API 並且不想看到已棄用的 prop 用法,請考慮執行 rename-components-to-slots
程式碼修改以處理 prop 重新命名。
npx @mui/x-codemod@latest v6.0.0/pickers/rename-components-to-slots <path>
請查看 RFC 以取得更多資訊。