mui5(Material Ui)我正在我的应用程序中使用nextjs。我正在努力实施dark mode。一切进展顺利。我想要一个功能,如果任何用户切换黑暗模式,那么它将保存在本地存储中。然后,当我刷新页面时,它会自动从本地存储获取值,并根据本地存储的值激活深色或浅色模式。如果用户第一次访问该站点,那么它应该自动激活系统首选项模式。我的意思是,如果本地存储中没有值,那么它应该自动激活系统首选项模式。我怎样才能做到这一点。
这是我的代码-
_app.js
export default function MyApp(props) {
const { Component, emotionCache = clientSideEmotionCache, pageProps } = props;
const [mode, setMode] = React.useState("light");
const colorMode = React.useMemo(
() => ({
// The dark mode switch would invoke this method
toggleColorMode: () => {
setMode((prevMode) =>
prevMode === 'light' ? 'dark' : 'light',
);
},
}),
[],
);
// Update the theme only if the mode changes
const muiTheme = React.useMemo(() => createTheme(theme(mode)), [mode]);
return (
<ColorModeContext.Provider value={colorMode}>
<CacheProvider value={emotionCache}>
<Head>
<meta name="viewport" content="initial-scale=1, width=device-width" />
</Head>
<ThemeProvider theme={muiTheme}>
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</CacheProvider>
</ColorModeContext.Provider>
);
}
MyApp.propTypes = {
Component: PropTypes.elementType.isRequired,
emotionCache: PropTypes.object,
pageProps: PropTypes.object.isRequired,
};
Run Code Online (Sandbox Code Playgroud)
切换按钮-
const theme = useTheme();
const colorMode = useContext(ColorModeContext);
<FormControlLabel
control={<MaterialUISwitch sx={{ m: 1 }} checked={theme.palette.mode === 'dark' ? false : true} />}
label=""
sx={{ mx: "0px" }}
onClick={colorMode.toggleColorMode}
/>
Run Code Online (Sandbox Code Playgroud)
您可以在此处查看我使用 Next.js 和 Material UI (5) 所做的示例:
\n我正在使用 Typescript,但如果你使用纯 JavaScript 也没关系
\n我们将有 2 个文件来独立修改特定属性。
\n黑暗主题.ts
\nimport { createTheme } from \'@mui/material/styles\'\nconst darkTheme = createTheme({\n palette: {\n mode: \'dark\',\n },\n})\nexport default darkTheme\nRun Code Online (Sandbox Code Playgroud)\n光主题.ts
\nimport { createTheme } from \'@mui/material/styles\'\nconst lightTheme = createTheme({\n palette: {\n mode: \'light\',\n },\n})\nexport default lightTheme\nRun Code Online (Sandbox Code Playgroud)\n这里重要的是从上下文中检索的值和功能,按钮样式或图标可以是任何东西。
\ninterface ThemeSwitcherButtonProps extends IconButtonProps { }\nconst ThemeSwitcherButton = ({ ...rest }: ThemeSwitcherButtonProps) => {\n const { themeMode, toggleTheme } = useThemeContext()\n return (\n <Tooltip\n title={themeMode === \'light\' ? `Switch to dark mode` : `Switch to light mode`}\n >\n <IconButton\n {...rest}\n onClick={toggleTheme}\n >\n {themeMode === \'light\' ? <DarkModeOutlined /> : <LightModeRounded />}\n </IconButton>\n </Tooltip>\n )\n}\nexport default ThemeSwitcherButton\nRun Code Online (Sandbox Code Playgroud)\n我们使用useMediaQuerymaterial ui 库来检查浏览器的首选项模式。该钩子适用于客户端渲染和 ssr。
我们还使用useLocalStorage钩子将状态保存在本地存储中,以便它被持久化。
我们用这个新的Provider包装了原来的Material UI ThemeProvider(重命名为MuiThemeProvider),所以那么在_app文件中只需要一个Provider
\n主题上下文.tsx
\nimport { createContext, ReactNode, useContext } from \'react\'\nimport { ThemeProvider as MuiThemeProvider, useMediaQuery } from \'@mui/material\'\n\nimport lightTheme from \'@/themes/light\'\nimport darkTheme from \'@/themes/dark\'\nimport useLocalStorage from \'@/react/hooks/useLocalStorage\'\n\nconst DARK_SCHEME_QUERY = \'(prefers-color-scheme: dark)\'\n\ntype ThemeMode = \'light\' | \'dark\'\ninterface ThemeContextType {\n themeMode: ThemeMode\n toggleTheme: () => void\n}\nconst ThemeContext = createContext<ThemeContextType>({} as ThemeContextType)\nconst useThemeContext = () => useContext(ThemeContext)\n\nconst ThemeProvider = ({ children }: { children: ReactNode }) => {\n const isDarkOS = useMediaQuery(DARK_SCHEME_QUERY)\n const [themeMode, setThemeMode] = useLocalStorage<ThemeMode>(\'themeMode\', isDarkOS ? \'light\' : \'dark\')\n\n const toggleTheme = () => {\n switch (themeMode) {\n case \'light\':\n setThemeMode(\'dark\')\n break\n case \'dark\':\n setThemeMode(\'light\')\n break\n default:\n }\n }\n\n return (\n <ThemeContext.Provider value={{ themeMode, toggleTheme }}>\n <MuiThemeProvider theme={themeMode === \'light\' ? lightTheme : darkTheme}>\n {children}\n </MuiThemeProvider>\n </ThemeContext.Provider>\n )\n}\n\nexport {\n useThemeContext,\n ThemeProvider\n}\nRun Code Online (Sandbox Code Playgroud)\n_app.tsx
\nexport default function MyApp(props: MyAppProps) {\n const { Component, emotionCache = clientSideEmotionCache, pageProps } = props\n const getLayout = Component.getLayout ?? ((page) => page)\n\n return (\n <CacheProvider value={emotionCache}>\n <Head>\n <meta name="viewport" content="initial-scale=1, width=device-width" />\n </Head>\n <ThemeProvider>\n {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}\n <CssBaseline />\n {getLayout(<Component {...pageProps} />)}\n </ThemeProvider>\n </CacheProvider>\n )\n}\nRun Code Online (Sandbox Code Playgroud)\n我从这里获取了源代码,并对其进行了一些修改,以便由于 ssr 和客户端渲染不匹配而可以与 Next.js 正常工作。
\nuseLocalStorage 还使用另一个 useEventListener 挂钩,以在打开的所有其他选项卡之间同步值的更改。
\nuseLocalStorage.tsx
\nexport default function MyApp(props: MyAppProps) {\n const { Component, emotionCache = clientSideEmotionCache, pageProps } = props\n const getLayout = Component.getLayout ?? ((page) => page)\n\n return (\n <CacheProvider value={emotionCache}>\n <Head>\n <meta name="viewport" content="initial-scale=1, width=device-width" />\n </Head>\n <ThemeProvider>\n {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}\n <CssBaseline />\n {getLayout(<Component {...pageProps} />)}\n </ThemeProvider>\n </CacheProvider>\n )\n}\nRun Code Online (Sandbox Code Playgroud)\nuseEventListener.tsx与网络中的完全相同。
\n此示例的所有代码都可以在我的github 存储库中找到,该存储库可以用作使用 Typescript、Nextjs 和 Material UI 的项目的起点。
\n您还可以在这里尝试一个工作示例。
\n| 归档时间: |
|
| 查看次数: |
4110 次 |
| 最近记录: |