从零开始-文件资源管理器-24-Next.js + antd 暗黑|明亮主题切换

当前主题默认为 "dard" 暗黑模式。这次将支持"暗黑模式"与"明亮模式"之间的切换。

开发

创建一个"主题"上下文文件

explorer/src/components/change-theme/change-theme-context.tsx

typescript 复制代码
'use client'
import createCtx from '@/lib/create-ctx'
import React from 'react'

export const ChangeThemeContext = createCtx<string>('')

export const ChangeThemeProvider: React.FC<React.ProviderProps<string>> = ({ value, children }) => {
  return <ChangeThemeContext.ContextProvider value={value}>{children}</ChangeThemeContext.ContextProvider>
}

再创建一个内联 cookie 的文件

explorer/src/components/change-theme/inject-cookie.tsx

javascript 复制代码
import { ChangeThemeProvider } from '@/components/change-theme/change-theme-context'
import React from 'react'
import { cookies } from 'next/headers'

const InjectCookieChangeThemeProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
  const theme = cookies().get('theme')?.value || 'dark'

  return <ChangeThemeProvider value={theme}>{children}</ChangeThemeProvider>
}

export default InjectCookieChangeThemeProvider

为 SSR 渲染时获取 cookie 内的 theme 的值,保持服务端与客户端渲染一致。避免主题切换闪屏。

该主题的改变会影响所有的组件渲染。所以将 InjectCookieChangeThemeProvider 内联 cookie 的组件插入最顶层的 layout 组件内。

explorer/src/app/layout.tsx

javascript 复制代码
...
import InjectCookieChangeThemeProvider from '@/components/change-theme/inject-cookie'
...

const RootLayout: React.FC<React.PropsWithChildren> = ({ children }) => (
  <html lang="en">
    <body className={inter.className}>
      <InjectCookieChangeThemeProvider>
        ...
      </InjectCookieChangeThemeProvider>
    </body>
  </html>
)
export default RootLayout

antd 的 ConfigProvider 上下文通过 ChangeThemeContext 上下文获取当前主题。

explorer/src/lib/antd-registry.tsx

javascript 复制代码
'use client'
...
import { ChangeThemeContext } from '@/components/change-theme/change-theme-context'
...

const AntdConfigProvider: React.FC<React.PropsWithChildren> = ({ children }) => {
  const select_theme = ChangeThemeContext.useStore()

  return (
    <ConfigProvider
      componentSize="small"
      theme={{
        algorithm: select_theme === 'dark' ? theme.darkAlgorithm : theme.defaultAlgorithm,
      }}
    >
      <Layout style={{ height: '100vh' }}>{children}</Layout>
    </ConfigProvider>
  )
}
...

创建一个改变主题的dropdown 下拉菜单,并插入页面右上角位置。

javascript 复制代码
'use client'
import React from 'react'
import { Button, Dropdown } from 'antd'
import { DarkIcon, LightIcon } from '@/components/icon/theme'
import { ChangeThemeContext } from '@/components/change-theme/change-theme-context'
import { useCookieState } from 'ahooks'

const ChangeThemeDropdown: React.FC = () => {
  const theme = ChangeThemeContext.useStore()
  const changeThemeDispatch = ChangeThemeContext.useDispatch()
  const [, changeCookies] = useCookieState('theme')

  return (
    <Dropdown
      menu={{
        selectedKeys: [theme],
        onClick: (item) => {
          changeThemeDispatch(item.key)
          changeCookies(item.key)
        },
        items: [
          { key: 'light', icon: <LightIcon />, label: '明亮模式' },
          { key: 'dark', icon: <DarkIcon />, label: '暗黑模式' },
        ],
      }}
    >
      <Button type="text" icon={theme === 'dark' ? <DarkIcon /> : <LightIcon />} />
    </Dropdown>
  )
}

export default ChangeThemeDropdown

当点击下拉菜单项时改变 ChangeThemeContext 上下文的值,并将当前改变值写入 cookie 内。

效果

到此,完成了改变主题的功能,通过将主题状态写入 cookie 内,保证服务端与客户端的渲染一致。

git-repo

yangWs29/share-explorer

相关推荐
code_YuJun7 分钟前
corepack 作用
前端
千寻girling8 分钟前
Koa.js 教程 | 一份不可多得的 Node.js 的 Web 框架 Koa.js 教程
前端·后端·面试
全栈前端老曹9 分钟前
【MongoDB】Node.js 集成 —— Mongoose ORM、Schema 设计、Model 操作
前端·javascript·数据库·mongodb·node.js·nosql·全栈
code_YuJun10 分钟前
pnpm-workspace.yaml
前端
天才熊猫君13 分钟前
“破案”笔记:iframe动态加载内容后,打印功能为何失灵?
前端
五月君_29 分钟前
炸裂!Claude Opus 4.6 与 GPT-5.3 同日发布:前端人的“自动驾驶“时刻到了?
前端·gpt
Mr Xu_34 分钟前
前端开发中CSS代码的优化与复用:从公共样式提取到CSS变量的最佳实践
前端·css
鹏北海-RemHusband1 小时前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构
LYFlied1 小时前
AI大时代下前端跨端解决方案的现状与演进路径
前端·人工智能
光影少年1 小时前
AI 前端 / 高级前端
前端·人工智能·状态模式