refactor(hooks): 状态管理模块拆分

This commit is contained in:
Soybean
2021-09-07 17:03:59 +08:00
parent 8601ce2ea1
commit 1128ae1870
23 changed files with 346 additions and 361 deletions

View File

@@ -1,5 +1,5 @@
<template>
<n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme="theme" :theme-overrides="app.themeOverrids">
<n-config-provider :locale="zhCN" :date-locale="dateZhCN" :theme="dark" :theme-overrides="theme.themeOverrids">
<n-loading-bar-provider>
<n-dialog-provider>
<n-notification-provider>
@@ -26,9 +26,9 @@ import {
NMessageProvider
} from 'naive-ui';
import { AppProviderContent } from '@/components';
import { useAppStore } from '@/store';
import { useThemeStore } from '@/store';
const app = useAppStore();
const theme = computed(() => (app.themeSettings.darkMode ? darkTheme : undefined));
const theme = useThemeStore();
const dark = computed(() => (theme.darkMode ? darkTheme : undefined));
</script>
<style scoped></style>

View File

@@ -5,13 +5,14 @@
<script lang="ts" setup>
import { useLoadingBar, useDialog, useMessage, useNotification } from 'naive-ui';
function registerNaiveTool() {
// 挂载naive组件的方法至window, 以便在路由钩子函数和请求函数里面调用
function registerNaiveUiTools() {
window.$loadingBar = useLoadingBar();
window.$dialog = useDialog();
window.$message = useMessage();
window.$notification = useNotification();
}
registerNaiveTool();
registerNaiveUiTools();
</script>
<style scoped></style>

View File

@@ -1,4 +1,3 @@
import AppProviderContent from './AppProviderContent/index.vue';
import ColorBlock from './ColorBlock/index.vue';
export { AppProviderContent, ColorBlock };
export { AppProviderContent };

View File

@@ -1 +1 @@
export { AppProviderContent, ColorBlock } from './common';
export { AppProviderContent } from './common';

View File

@@ -1,2 +1,2 @@
export { UserInfo } from './business';
export { ThemeSettings, NavMode } from './app';
export { ThemeSettings, NavMode } from './theme';

View File

@@ -35,6 +35,7 @@ interface OtherColor {
}
export type NavMode = keyof typeof EnumNavMode;
type NavTheme = keyof typeof EnumNavTheme;
interface NavStyle {
@@ -56,8 +57,6 @@ interface HeaderStyle {
}
interface MenuStyle {
/** 折叠菜单 */
collapsed: boolean;
/** 菜单宽度 */
width: number;
/** 菜单折叠时的宽度 */

View File

@@ -10,7 +10,7 @@ import { computed } from 'vue';
import { useAppStore } from '@/store';
const app = useAppStore();
const showTitle = computed(() => !app.themeSettings.menuStyle.collapsed);
const showTitle = computed(() => !app.menu.collapsed);
const title = import.meta.env.VITE_APP_TITLE as string;
</script>
<style scoped></style>

View File

@@ -1,7 +1,7 @@
<template>
<n-divider title-placement="center">深色主题</n-divider>
<div class="flex-center">
<n-switch :value="app.themeSettings.darkMode" @update:value="handleDarkMode">
<n-switch :value="theme.darkMode" @update:value="handleDarkMode">
<template #checked>
<icon-mdi-white-balance-sunny class="text-14px text-primary" />
</template>
@@ -14,10 +14,10 @@
<script lang="ts" setup>
import { NDivider, NSwitch } from 'naive-ui';
import { useAppStore } from '@/store';
import { useThemeStore } from '@/store';
const app = useAppStore();
const { handleDarkMode } = useAppStore();
const theme = useThemeStore();
const { handleDarkMode } = useThemeStore();
</script>
<style scoped>
:deep(.n-switch__rail) {

View File

@@ -5,7 +5,7 @@
v-for="item in modeList"
:key="item.mode"
:mode="item.mode"
:checked="app.themeSettings.navStyle.mode === item.mode"
:checked="theme.navStyle.mode === item.mode"
@click="setNavMode(item.mode)"
/>
</n-space>
@@ -16,15 +16,15 @@ import { NDivider, NSpace } from 'naive-ui';
import { EnumNavMode } from '@/enum';
import type { NavMode } from '@/interface';
import { NavType } from './components';
import { useAppStore } from '@/store';
import { useThemeStore } from '@/store';
interface ModeList {
mode: NavMode;
label: string;
}
const app = useAppStore();
const { setNavMode } = useAppStore();
const theme = useThemeStore();
const { setNavMode } = useThemeStore();
const modeList: ModeList[] = [
{ mode: 'vertical', label: EnumNavMode.vertical },

View File

@@ -3,20 +3,20 @@
<n-space vertical size="large">
<div class="flex-y-center justify-between">
<span>分割菜单</span>
<n-switch :value="app.themeSettings.menuStyle.splitMenu" @update:value="handleSplitMenu" />
<n-switch :value="theme.menuStyle.splitMenu" @update:value="handleSplitMenu" />
</div>
<div class="flex-y-center justify-between">
<span>固定头部</span>
<n-switch :value="app.themeSettings.headerStyle.fixed" @update:value="handleFixedHeader" />
<n-switch :value="theme.headerStyle.fixed" @update:value="handleFixedHeader" />
</div>
</n-space>
</template>
<script lang="ts" setup>
import { NDivider, NSpace, NSwitch } from 'naive-ui';
import { useAppStore } from '@/store';
import { useThemeStore } from '@/store';
const app = useAppStore();
const { handleSplitMenu, handleFixedHeader } = useAppStore();
const theme = useThemeStore();
const { handleSplitMenu, handleFixedHeader } = useThemeStore();
</script>
<style scoped></style>

View File

@@ -1,18 +1,18 @@
<template>
<n-divider title-placement="center">系统主题</n-divider>
<n-grid :cols="8">
<n-grid-item v-for="color in app.themeSettings.themeColorList" :key="color">
<color-block :color="color" :checked="color === app.themeSettings.themeColor" @click="setThemeColor(color)" />
<n-grid-item v-for="color in theme.themeColorList" :key="color">
<color-block :color="color" :checked="color === theme.themeColor" @click="setThemeColor(color)" />
</n-grid-item>
</n-grid>
</template>
<script lang="ts" setup>
import { NDivider, NGrid, NGridItem } from 'naive-ui';
import { useAppStore } from '@/store';
import { ColorBlock } from '@/components';
import { useThemeStore } from '@/store';
import { ColorBlock } from '../common';
const app = useAppStore();
const { setThemeColor } = useAppStore();
const theme = useThemeStore();
const { setThemeColor } = useThemeStore();
</script>
<style scoped></style>

View File

@@ -0,0 +1,3 @@
import ColorBlock from './ColorBlock.vue';
export { ColorBlock };

View File

@@ -5,8 +5,8 @@
:native-scrollbar="false"
:inverted="inverted"
collapse-mode="width"
:collapsed="app.themeSettings.menuStyle.collapsed"
:collapsed-width="app.themeSettings.menuStyle.collapsedWidth"
:collapsed="app.menu.collapsed"
:collapsed-width="theme.menuStyle.collapsedWidth"
:width="menuWidth"
@collapse="handleMenuCollapse(true)"
@expand="handleMenuCollapse(false)"
@@ -30,27 +30,27 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { NLayout, NLayoutSider, NLayoutHeader, NLayoutContent, NLayoutFooter } from 'naive-ui';
import { useAppStore } from '@/store';
import { useThemeStore, useAppStore } from '@/store';
import { GlobalHeader, GlobalLogo, GlobalMenu, SettingDrawer } from './components';
const theme = useThemeStore();
const app = useAppStore();
const { handleMenuCollapse } = useAppStore();
const position = computed(() => (app.themeSettings.headerStyle.fixed ? 'absolute' : 'static'));
const position = computed(() => (theme.headerStyle.fixed ? 'absolute' : 'static'));
const menuWidth = computed(() => {
const { collapsed, collapsedWidth, width } = app.themeSettings.menuStyle;
const { collapsed } = app.menu;
const { collapsedWidth, width } = theme.menuStyle;
return collapsed ? collapsedWidth : width;
});
const inverted = computed(() => {
const { theme } = app.themeSettings.navStyle;
return theme !== 'light';
return theme.navStyle.theme !== 'light';
});
const headerInverted = computed(() => {
const { theme } = app.themeSettings.navStyle;
return theme !== 'dark' ? inverted.value : !inverted.value;
return theme.navStyle.theme !== 'dark' ? inverted.value : !inverted.value;
});
const headerHeight = computed(() => {
const { height } = app.themeSettings.headerStyle;
const { height } = theme.headerStyle;
return `${height}px`;
});
</script>

View File

@@ -25,6 +25,7 @@ async function setupApp() {
app.mount('#app', true);
// 配置windicss暗黑主题
setupWindicssDarkMode();
}

View File

@@ -1,8 +1,8 @@
import { watch } from 'vue';
import { useAppStore } from '@/store';
import { useThemeStore } from '@/store';
export default function setupWindicssDarkMode() {
const app = useAppStore();
const theme = useThemeStore();
const DARK_CLASS = 'dark';
@@ -19,7 +19,7 @@ export default function setupWindicssDarkMode() {
}
watch(
() => app.themeSettings.darkMode,
() => theme.darkMode,
newValue => {
if (newValue) {
addDarkClass();

View File

@@ -7,4 +7,4 @@ export function setupStore(app: App) {
app.use(store);
}
export { useAppStore, useAuthStore } from './modules';
export { useThemeStore, useAppStore, useAuthStore } from './modules';

View File

@@ -1,77 +1,42 @@
import { defineStore } from 'pinia';
import type { GlobalThemeOverrides } from 'naive-ui';
import { themeSettings } from '@/settings';
import { store } from '@/store';
import type { ThemeSettings, NavMode } from '@/interface';
import { getHoverAndPressedColor } from './helpers';
/** app状态 */
interface AppState {
/** 主题配置 */
themeSettings: ThemeSettings;
/** 主题配置抽屉 */
menu: MenuState;
settingDrawer: SettingDrawer;
}
/** 菜单状态 */
interface MenuState {
/** 菜单折叠 */
collapsed: boolean;
}
/** 设置抽屉的状态 */
interface SettingDrawer {
/** 设置抽屉可见性 */
visible: boolean;
}
const appStore = defineStore({
id: 'app-store',
state: (): AppState => ({
themeSettings,
menu: {
collapsed: false
},
settingDrawer: {
visible: false
}
}),
getters: {
/** naive UI主题配置 */
themeOverrids(): GlobalThemeOverrides {
const {
themeColor: primaryColor,
otherColor: { info: infoColor, success: successColor, warning: warningColor, error: errorColor }
} = this.themeSettings;
const { hover: primaryColorHover, pressed: primaryColorPressed } = getHoverAndPressedColor(primaryColor);
const { hover: infoColorHover, pressed: infoColorPressed } = getHoverAndPressedColor(infoColor);
const { hover: successColorHover, pressed: successColorPressed } = getHoverAndPressedColor(successColor);
const { hover: warningColorHover, pressed: warningColorPressed } = getHoverAndPressedColor(warningColor);
const { hover: errorColorHover, pressed: errorColorPressed } = getHoverAndPressedColor(errorColor);
const colorLoading = primaryColor;
return {
common: {
primaryColor,
primaryColorHover,
primaryColorPressed,
infoColor,
infoColorHover,
infoColorPressed,
successColor,
successColorHover,
successColorPressed,
warningColor,
warningColorHover,
warningColorPressed,
errorColor,
errorColorHover,
errorColorPressed
},
LoadingBar: {
colorLoading
}
};
}
},
actions: {
/** 折叠/展开菜单 */
handleMenuCollapse(collapsed: boolean) {
this.themeSettings.menuStyle.collapsed = collapsed;
this.menu.collapsed = collapsed;
},
/** 切换折叠/展开菜单 */
toggleMenu() {
this.themeSettings.menuStyle.collapsed = !this.themeSettings.menuStyle.collapsed;
this.menu.collapsed = !this.menu.collapsed;
},
/** 打开配置抽屉 */
openSettingDrawer() {
@@ -80,26 +45,6 @@ const appStore = defineStore({
/** 关闭配置抽屉 */
closeSettingDrawer() {
this.settingDrawer.visible = false;
},
/** 设置暗黑模式 */
handleDarkMode(isDark: boolean) {
this.themeSettings.darkMode = isDark;
},
/** 设置系统主题颜色 */
setThemeColor(color: string) {
this.themeSettings.themeColor = color;
},
/** 设置导航栏模式 */
setNavMode(mode: NavMode) {
this.themeSettings.navStyle.mode = mode;
},
/** 折叠菜单 */
handleSplitMenu(isSplit: boolean) {
this.themeSettings.menuStyle.splitMenu = isSplit;
},
/** 固定头部 */
handleFixedHeader(isFixed: boolean) {
this.themeSettings.headerStyle.fixed = isFixed;
}
}
});

View File

@@ -1,4 +1,5 @@
import useThemeStore from './theme';
import useAppStore from './app';
import useAuthStore from './auth';
export { useAppStore, useAuthStore };
export { useThemeStore, useAppStore, useAuthStore };

View File

@@ -0,0 +1,8 @@
import { brightenColor, darkenColor } from '@/utils';
export function getHoverAndPressedColor(color: string) {
return {
hover: brightenColor(color),
pressed: darkenColor(color)
};
}

View File

@@ -0,0 +1,81 @@
import { defineStore } from 'pinia';
import type { GlobalThemeOverrides } from 'naive-ui';
import { themeSettings } from '@/settings';
import { store } from '@/store';
import type { ThemeSettings, NavMode } from '@/interface';
import { getHoverAndPressedColor } from './helpers';
type ThemeState = ThemeSettings;
const themeStore = defineStore({
id: 'theme-store',
state: (): ThemeState => ({
...themeSettings
}),
getters: {
/** naive UI主题配置 */
themeOverrids(): GlobalThemeOverrides {
const {
themeColor: primaryColor,
otherColor: { info: infoColor, success: successColor, warning: warningColor, error: errorColor }
} = this;
const { hover: primaryColorHover, pressed: primaryColorPressed } = getHoverAndPressedColor(primaryColor);
const { hover: infoColorHover, pressed: infoColorPressed } = getHoverAndPressedColor(infoColor);
const { hover: successColorHover, pressed: successColorPressed } = getHoverAndPressedColor(successColor);
const { hover: warningColorHover, pressed: warningColorPressed } = getHoverAndPressedColor(warningColor);
const { hover: errorColorHover, pressed: errorColorPressed } = getHoverAndPressedColor(errorColor);
const colorLoading = primaryColor;
return {
common: {
primaryColor,
primaryColorHover,
primaryColorPressed,
infoColor,
infoColorHover,
infoColorPressed,
successColor,
successColorHover,
successColorPressed,
warningColor,
warningColorHover,
warningColorPressed,
errorColor,
errorColorHover,
errorColorPressed
},
LoadingBar: {
colorLoading
}
};
}
},
actions: {
/** 设置暗黑模式 */
handleDarkMode(isDark: boolean) {
this.darkMode = isDark;
},
/** 设置系统主题颜色 */
setThemeColor(color: string) {
this.themeColor = color;
},
/** 设置导航栏模式 */
setNavMode(mode: NavMode) {
this.navStyle.mode = mode;
},
/** 折叠菜单 */
handleSplitMenu(isSplit: boolean) {
this.menuStyle.splitMenu = isSplit;
},
/** 固定头部 */
handleFixedHeader(isFixed: boolean) {
this.headerStyle.fixed = isFixed;
}
}
});
export default function useThemeStore() {
return themeStore(store);
}