27 暗黑主题样式优化 - udo-bit/naive_admin_pro GitHub Wiki

目标

完成暗黑主题样式的优化

动态切换布局bug

上节课我们完成了动态暗黑主题的切换,但是还存在一些bug,当我们切到亮色的时候,发现我们的内容布局部分还是暗黑模式。 我们切到stores/app.ts中监听我们布局样式的变化,根据样式变化动态处理我们的布局

  watch(() => layout.layoutStyle, () => {
    if (layout.layoutStyle === 'dark')
      toggleDark(true)

    else
      toggleDark(false)
  })

添加暗黑主题切换功能

接下来我们来添加一下切换暗黑主题的功能。 我们切到setting-drawer中的checkbox-layout.vue中,添加dark属性:

const props = withDefaults(defineProps<{
  layout?: 'mix' | 'side' | 'top'
  inverted?: boolean
  checked?: boolean
  title?: string | (() => VNodeChild)
  dark?: boolean
}>(), {
  layout: 'top',
  inverted: false,
  checked: false,
})

如果主题是dark模式的话,我们就让顶部和侧边栏都为反色。

const headerClass = computed(() => {
+  if (props.layout === 'mix' || props.layout === 'top' || props.dark) {
    return [
      'bg-[var(--inverted-color)]',
    ]
  }
  if (props.layout === 'side') {
    return [
      'bg-[var(--base-color)]',
    ]
  }

  return []
})

const siderClass = computed(() => {
  if (props.layout === 'mix') {
    return [
      'bg-[var(--base-color)]',
      'h-75%',
      'bottom-0',
    ]
  }
  if (props.layout === 'side') {
    return [
      'h-100%',
+      `bg-[var(--${(props.inverted || props.dark) ? 'inverted' : 'base'}-color)]`,
    ]
  }
  return []
})

在index.vue中添加支持dark模式:

<template>
  <Container v-if="layoutStyleList" title="布局风格配置">
        <n-space size="large">
          <template v-for="item in layoutStyleList" :key="item.id">
            <CheckboxLayout
              :title="item.title"
              :layout="item.key"
 +             :dark="item.dark"
              :inverted="item.inverted"
              :checked="item.id === layoutStyle"
              @click="() => $emit('update:layoutStyle', item.id)"
            />
          </template>
        </n-space>
      </Container>
</template>

在config/layout-theme.ts中添加对暗黑主题的类型支持

export interface LayoutType {
  id: string
  key: 'mix' | 'side' | 'top'
  title: string
  inverted?: boolean
+  dark?:boolean
}

在stores/app.ts中添加暗黑模式主题:

const layoutStyleList = computed<LayoutType[]>(() => {
    const list: LayoutType[] = [
      {
        id: 'light',
        key: 'side',
        title: '亮色风格',
      },
    ]

    if (layout.layout !== 'mix') {
      list.push({
        id: 'inverted',
        key: 'side',
        inverted: true,
        title: '反转色风格',
      })
    }
    else {
      if (layout.layoutStyle !== 'dark')
        updateLayoutStyle('light')
    }
    list.push({
      id: 'dark',
      key: 'side',
      title: '暗色风格',
      dark:true
    })
    return list
  })

接下来我们看到当我们切换到暗黑模式的时候,整个的布局风格都变成了一样的格式和样子,但这不是我们想要的,所以接下来我们优化一下整个的样式。 首先我们再config中创建一个pro-theme.ts的文件用于存放我们的全局样式,然后直接复制我们这一部分的样式代码。

import { merge } from 'lodash-es'

import type { GlobalTheme } from 'naive-ui'
import {
  cardDark,
  drawerDark,
  elementDark,
  layoutDark,
  listDark,
  menuDark,
  darkTheme as naiveDarkTheme,
} from 'naive-ui'
const commonColor: Record<string, any> = {
  bgColor: '#242525',
}

export const darkTheme: GlobalTheme = merge({}, naiveDarkTheme, {
  common: {
    baseColor: '#2A2C2C',
  },
  Layout: {
    ...layoutDark,
    self(_vars) {
      return {
        ...layoutDark.self?.(_vars),
        color: commonColor.bgColor,
        headerColor: commonColor.bgColor,
        siderColor: commonColor.bgColor,
        footerColor: commonColor.bgColor,
      }
    },
  },
  Card: {
    ...cardDark,
    self(_vars) {
      return {
        ...cardDark.self?.(_vars),
        color: commonColor.bgColor,
      }
    },
  },
  Drawer: {
    ...drawerDark,
    self(_vars) {
      return {
        ...drawerDark.self?.(_vars),
        color: commonColor.bgColor,
      }
    },
  },
  Menu: {
    ...menuDark,
    self(_vars) {
      return {
        ...menuDark.self?.(_vars),
        color: commonColor.bgColor,
      }
    },
  },
  List: {
    ...listDark,
    self(_vars) {
      return {
        ...listDark.self?.(_vars),
        color: commonColor.bgColor,
      }
    },
  },
  Element: {
    ...elementDark,
    common: {
      ...elementDark.common,
      baseColor: commonColor.bgColor,
    },
  },
} as Partial<GlobalTheme>)

export const layoutDarkTheme = darkTheme.Layout

export const elementDarkTheme = darkTheme.Element

由于文件中引入了lodash-es我们先来安装一下

pnpm add @types/lodash-es lodash-es -D

替换暗黑主题在stores/app.ts

import { darkTheme } from '~/config/pro-theme'

const layoutTheme = computed(() => {
    if (layout.layoutStyle === 'dark')
      return darkTheme

    return undefined
})

我们可以看到,当我们在切换主题的时候,就保证了我们的样式的问题,接下里我们再来优化一下我们的侧边栏阴影和顶部的阴影。 我们在styles/vars.css中添加对应的阴影css变量

html{
    --pro-admin-layout-content-bg: #f0f2f5;
    --pro-admin-layout-box-shadow: 0 1px 3px 0 rgba(0,0,0,.18);
+    --pro-admin-layout-shadow-sider: 2px 0 8px 0 rgb(29 35 41 / 5%);
+    --pro-admin-layout-shadow-header: 0 1px 4px rgb(0 21 41 / 8%);
}


html.dark{
    --pro-admin-layout-content-bg: #2A2C2C;
    --pro-admin-layout-box-shadow: 0 1px 3px 0 rgba(13,13,13,.18);
+    --pro-admin-layout-shadow-sider: rgba(13, 13, 13, 0.65) 0px 2px 8px 0px;
+    --pro-admin-layout-shadow-header: rgb(13 13 13 / 65%) 0px 2px 8px 0px;
}

然后创建一个自定义css样式文件custom.css:

.pro-admin-layout-header{
    box-shadow: var(--pro-admin-layout-shadow-header);
}
.pro-admin-layout-sider{
    box-shadow: var(--pro-admin-layout-shadow-sider);
}

然后再index.css中导入:

@import "vars.css";
+ @import "custom.css";

然后我们在布局中添加我们的类: 在layouts中的mix-layout:

<n-layout-header
  inverted
 + class="pro-admin-layout-header pro-admin-mix-layout-header flex justify-between items-center px-4">
  <div class="flex items-center">
    <Logo :src="logo" />
    <Title :title="title" />
  </div>
  <slot name="headerRight">
    <div>
      右侧
    </div>
  </slot>
</n-layout-header>

在 mobile-layout中:

<n-layout-header
      :inverted="headerInverted"
      class="pro-admin-layout-header pro-admin-mix-layout-header flex justify-between items-center px-4"
    >
// ...
</h-layout-header>

在side-layout中:

<n-layout-header class="pro-admin-mix-layout-header flex justify-between items-center px-4">
  // ...
</n-layout-header>

在top-layout中:

<n-layout-header
      :inverted="inverted"
+      class="pro-admin-layout-header pro-admin-mix-layout-header flex justify-between items-center px-4"
    >
      /// ...
</n-layout-header>

在 common/layout-sider中

<template>
 + <n-layout-sider class="pro-admin-layout-sider" collapse-mode="width">
    <slot />
  </n-layout-sider>
</template>

测试效果

⚠️ **GitHub.com Fallback** ⚠️