- Published on
使用nextjs 实现暗黑模式
- Authors
- Name
- Azimuth Ti
Overview
使用 Next.js 社区提供的一个主题管理库 next-themes,可以轻松地实现暗黑模式切换,以下代码基于Nextjs15 + tailwindcss 4.x实现(3.x版本略有不同,查阅其他文档)
1、初始化项目
根据官方步骤初始化nextjs项目(使用typescript)
npx create-next-app@latest
2、进入项目目录安装依赖库
项目中用到了两个图标,依赖了lucide-react库
pnpm install next-themes lucide-react
3、修改默认的global.css文件
- @media (prefers-color-scheme: dark) {
- :root {
- --background: #0a0a0a;
- --foreground: #ededed;
- }
- }
+ @custom-variant dark (&:where(.dark, .dark *));
4、自定义ThemeProvider类
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({ children }: { children: React.ReactNode }) {
return (
<NextThemesProvider
attribute="class"
defaultTheme={"light"}
enableSystem
disableTransitionOnChange
>
{children}
</NextThemesProvider>
);
}
5、修改app目录下面的layout.tsx
在layout.tsx中import上面自定义的ThemeProvider类,并做如下代码修改
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
- {children}
+ <ThemeProvider> {children}</ThemeProvider>
</body>
</html>
);
}
6、自定义一个触发主题模式切换的组件
// /app/components/ThemeSwitch.tsx
'use client'
import { Moon, Sun } from 'lucide-react'
import { useTheme } from 'next-themes'
export default function ThemeSwitch() {
const { theme, setTheme } = useTheme()
return (
<>
<button
onClick={() => {
console.log('theme---->', theme)
setTheme(theme == 'dark' ? 'light' : 'dark')
}}
>
{theme == 'dark' ? (
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 transition-all dark:fill-white dark:stroke-white" />
) : (
<Moon className="h-[1.2rem] w-[1.2rem] fill-black transition-all" />
)}
</button>
</>
)
}
7、应用
在需要的位置引入主题模式切换的组件即可。
这里用默认的/app/page.tsx文件为例:
import ThemeSwitch from "@/components/ThemeSwitch";
import Image from "next/image";
export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)] dark:bg-black">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start dark:bg-black">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ThemeSwitch />
</main>
</div>
);
}