从0开始的中后台管理系统-7(项目完结主题切换)

54 阅读3分钟

         ​编辑

        这是项目的完整知识点涉及,前篇博客都有提及,这篇就是最后一个功能主题切换,首先主题切换需要在状态管理中设置一个变量isDark,然后为了持久化storage.get去获取,或者初始值为false,然后设置更新方法。

import resso from 'resso'
import { create } from 'zustand'
import type { User } from '@/types/api'
import storage from '@/utils/storage'
//resso 状态管理有类型推导 直接token:''会认为是string
//resso 直接在resso({})对象中配置存的状态管理 赋值直接通过引入store对象直接.=赋值就可以了
//操作方法也可以直接写在resso中
const store = resso({
  token: '',
  userInfo: {
    create: 0,
    mobile: '',
    job: '',
    deptId: '',
    deptName: '',
    role: 0,
    roleList: '',
    state: 0,
    userEmail: '',
    userId: 0,
    userImg: '',
    userName: '',
    _id: ''
  },
  isDark: storage.get('isDark') || false,
  updateTheme(isDark: boolean) {
    store.isDark = isDark
  },
  updataUserInfo(userInfo: User.UserItem) {
    store.userInfo = userInfo
  },
  updataToken(token: string) {
    store.token = token
  }
})
export default store

        然后在导航栏切换的时候,触发监听事件,用的antd组件Switch会自动把当前的布尔值作为参数传递,然后我们用document.docomentElement绑定html标签然后.classList.add给html添加class属性dark就可以设置暗黑主题了。因为再次点击就删除classList.remove('dark')这样大体除了标签内部以及组件的暗黑样式就实现了。

:root {
  --dark-bg-color: #fff;
  --dark-color: #000;
  --dark-home-bg-color: #f0f2f5;
  --dark-logo-color: #001529;
}

.dark {
  --dark-bg-color: #141414;
  --dark-color: #fff;
  --dark-home-bg-color: #000;
  --dark-logo-color: #141414;
}
import { MenuUnfoldOutlined } from '@ant-design/icons'
import { Breadcrumb, Dropdown, Switch } from 'antd'
import type { MenuProps } from 'antd'
import styles from './index.module.less'
import store, { useStore } from '@/store'
import storage from '@/utils/storage'
import BreadCrumb from './BreadCrumb'
import { useEffect } from 'react'
export default function NavHeader() {
  const userInfo = useStore(state => state.userInfo)
  useEffect(() => {
    handleSwitch(store.isDark)
  }, [])
  const items: MenuProps['items'] = [
    {
      key: 'emali',
      label: 邮箱:${store.userInfo.userEmail}
    },
    {
      key: 'logout',
      label: 退出
    }
  ]
  const onClick: MenuProps['onClick'] = ({ key }) => {
    if (key === 'logout') {
      storage.remove('token')
      //location.href = '/login?...' 表示重定向到登录页面,并把当前页面地址编码后作为参数传过去。
      location.href = '/login?callback=' + encodeURIComponent(location.href)
    }
  }
  const handleSwitch = (isDark: boolean) => {
    if (isDark) {
      // document.documentElement.dataset.theme = 'dark'
      document.documentElement.classList.add('dark')
    } else {
      // document.documentElement.dataset.theme = 'light'
      document.documentElement.classList.remove('dark')
    }
    storage.set('isDark', isDark)
    store.updateTheme(isDark)
  }
  return (
    <div className={styles.navHeader}>
      <div className={styles.left}>
        <MenuUnfoldOutlined />
        <BreadCrumb />
      </div>
      <div className='right'>
        <Switch
          checked={store.isDark}
          checkedChildren='暗黑'
          unCheckedChildren='默认'
          onChange={handleSwitch}
          style={{ marginRight: '10px' }}
        />
        <Dropdown menu={{ items, onClick }} trigger={['click']}>
          <span className={styles.nickName}>{userInfo.userName}</span>
        </Dropdown>
      </div>
    </div>
  )
}

        那么其他的标签内部样式就需要把所有的背景色和字体色去动态设置用var(--dark-color)以及var(--dark-bg-color)设置。这样就会根据当前html是:root还是:dark自行更换了。本质上都是样式继承于html标签。

.content {
  background-color: var(--dark-home-bg-color);
  //width: calc(100vw-200px);
  height: calc(100vh - 90px);
  padding: 20px;
  overflow: auto;
}
.wrapper {
  min-height: calc(100vh - 210px);
}

        但是antd框架ui组件就不能够去继承了,所以需要我们用组件的主题切换方式,通过在根标签组件嵌套configProvider去添加主题算法,也是通过isDark去判断用黑暗算法还是默认算法,以及token配置主题色。

import { BrowserRouter, RouterProvider } from 'react-router-dom'
import router from './router/index'
import { ConfigProvider } from 'antd'
import { App as AntdApp, theme } from 'antd'
import store from './store'
import AntdGlobal from './utils/AntdGlobal'
import './styles/theme.less'
import './App.less'
export default function App() {
  const isDark = store.isDark
  return (
    <ConfigProvider
      theme={{
        token: { colorPrimary: '#ed6c00' },
        algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm
      }}
    >
      <AntdApp>
        <AntdGlobal />
        <RouterProvider router={router} />
      </AntdApp>
    </ConfigProvider>
  )
  // return (
  //   <BrowserRouter>
  //     <Router />
  //   </BrowserRouter>
  // )
}

效果图

​编辑

​编辑