组件库使用的是styled-components
1.window.matchMedia
首先要声明支持light和dark两种模式。
声明有两种方式:
- 在css中
:root{
color-scheme:light dark;
}
- 在head中
<meta name="color-scheme" content="light dark">
之后在js中通过window.matchMedia查询prefers-color-scheme: dark并监听属性变化,如果命中则为暗黑模式
样式的改变通过styled-components的theme实现,具体看styled-components的官方文档styled-components: Documentation
import { ThemeProvider } from "styled-components"
import { lightTheme, darkTheme } from "@/styles/theme"
import React, { PropsWithChildren, useEffect, useState } from "react"
import { Text } from "./Atom"
enum ThemeType {
LIGHT,
DARK,
}
const Providers: React.FC<PropsWithChildren> = ({ children }) => {
const [curTheme, setCurTheme] = useState<ThemeType>(ThemeType.LIGHT)
const handleChangeTheme = (e: MediaQueryListEvent | MediaQueryList) => {
const { matches } = e
if (matches) {
setCurTheme(ThemeType.DARK)
} else {
setCurTheme(ThemeType.LIGHT)
}
}
useEffect(() => {
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
//获得初始模式
handleChangeTheme(mediaQuery)
//监听模式变化
mediaQuery.addEventListener("change", handleChangeTheme)
return () => {
mediaQuery.removeEventListener("change", handleChangeTheme)
}
}, [])
return (
<ThemeProvider theme={curTheme === ThemeType.DARK ? darkTheme : lightTheme}>
<Text>???</Text>
{children}
</ThemeProvider>
)
}
export default Providers
2.next-theme插件
https://github.com/pacocoursey/next-themes
引入next-theme,包裹一层插件提供的provider,在组件中使用useTheme获取当前模式
"use client"
import { ThemeProvider } from "styled-components"
import { lightTheme, darkTheme } from "@/styles/theme"
import { ThemeProvider as NextThemeProvider, useTheme } from "next-themes"
import React, { PropsWithChildren, useEffect, useState } from "react"
import { Text } from "./Atom"
enum ThemeType {
LIGHT = "light",
DARK = "dark",
}
const StyledThemeProvider: React.FC<PropsWithChildren> = ({ children }) => {
const [mounted, setMounted] = useState<boolean>(false)
const { resolvedTheme: curTheme } = useTheme()
useEffect(() => {
setMounted(true)
}, [])
return mounted ? (
<ThemeProvider theme={curTheme === ThemeType.DARK ? darkTheme : lightTheme}
>
<Text>???</Text>
{children}
</ThemeProvider>
) : null
}
const Providers: React.FC<PropsWithChildren> = ({ children }) => {
return (
<NextThemeProvider>
<StyledThemeProvider>{children}</StyledThemeProvider>
</NextThemeProvider>
)
}
export default Providers
参考: