24 整体风格配置开发 - udo-bit/naive_admin_pro GitHub Wiki

目标

实现整体风格的配置开发

开发

整体风格:比如我们的侧边栏布局模式和顶部布局模式,我们可以切换我们的侧边栏是正常的颜色还是反转色。 所以我们还需要实现我们的整体风格的配置和开发。

我们在layouts/setting-drawer/index.vue中,增加一个整体风格设置的配置。

<script lang="ts" setup>
  const props = withDefaults(defineProps<{
    floatTop?: number | string
    drawerWidth?: number | string
    layout?: 'side' | 'top' | 'mix'
    layoutStyle?: 'light' | 'inverted'
  }>(), {
    floatTop: 240,
    drawerWidth: 300,
  })

  const emit = defineEmits(['update:layout', 'update:layoutStyle'])


  const onChangeStyle = (val: string) => {
    emit('update:layoutStyle', val)
  }
  
	const styles = $ref([
    {
      id: 'light',
      key: 'side',
      title: '亮色风格',
    },
    {
      id: 'inverted',
      key: 'side',
      inverted: true,
      title: '反转色风格',
    },
	])
</script>

<template>
  <SettingContainer title="整体风格设置">
    <n-space size="large">
      <template v-for="item in styles" :key="item.id">
        <CheckboxLayout
          :title="item.title"
          :layout="item.key"
          :inverted="item.inverted"
          :checked="item.id === layoutStyle"
          @click="onChangeStyle(item.id)"
        />
      </template>
    </n-space>
  </SettingContainer>
</template>

接下来我们需要增加一个配置项在config/layout-theme.ts的文件中

export interface LayoutTheme {
+  layoutStyle: 'dark' | 'light' | 'inverted'
}

export const layoutThemeConfig: LayoutTheme = {
+ layoutStyle: 'light',
}

然后再base-layout中增加一个双向绑定的实现:

<template>
    <SettingDrawer v-model:layout-style="layout.layoutStyle" v-model:layout="layout.layout" />
</template>

测试效果,我们发现当我们切换的时候并不会生效,这是因为我们没有在各个布局中设置,接下来我们在各个布局中配置一下反转色功能。 base-layout/index.vue

<template>
<SideLayout
  v-if="layout.layout === 'side'"
  v-model:collapsed="layout.collapsed"
  :logo="layout.logo"
  :title="layout.title"
  :inverted="layout.layoutStyle === 'inverted'"
  :show-sider-trigger="layout.showSiderTrigger"
  :sider-width="layout.siderWidth"
  :sider-collapsed-width="layout.siderCollapsedWidth"
>
  <template #headerRight>
    <div>
      测试右侧插槽
    </div>
  </template>
  <router-view />
</SideLayout>
<TopLayout
  v-if="layout.layout === 'top'"
  :logo="layout.logo"
  :inverted="layout.layoutStyle === 'inverted'"
  :title="layout.title"
>
  <template #headerRight>
    <div>
      测试右侧插槽
    </div>
  </template>
  <router-view />
</TopLayout>
</template>

由于我们的混合布局是不支持反转色的,所以在我们切换布局的同时我们要改变一下我们的整体风格的样式。 所以我们需要将我们的布局列表单独抽离出来。 在config/layout-theme中增加一个类型配置

export interface LayoutType {
  key: string
  id: string
  inverted?: boolean
  title?: string
}

然后在setting-drawer/index.vue中,删除定义写死的布局,然后改成动态传入的方式。如下(只写改动代码)

<script lang="ts" setup>
import type { LayoutType } from '~/config/layout-theme'

const props = withDefaults(defineProps<{
  layoutList?: LayoutType[]
  layoutStyleList?: LayoutType[]
}>(), {
})
</script>

<template>
  <n-drawer v-model:show="show" :width="drawerWidth">
    <n-drawer-content>
      <SettingContainer v-if="layoutStyleList" title="整体风格设置">
        <n-space size="large">
          <template v-for="item in layoutStyleList" :key="item.id">
            <CheckboxLayout
              :title="item.title"
              :layout="item.key"
              :inverted="item.inverted"
              :checked="item.id === layoutStyle"
              @click="onChangeStyle(item.id)"
            />
          </template>
        </n-space>
      </SettingContainer>
      <SettingContainer v-if="layoutList" title="导航模式">
        <n-space size="large">
          <template v-for="item in layoutList" :key="item.key">
            <CheckboxLayout :title="item.title" :layout="item.key" :checked="item.key === layout" @click="onChange(item.key)" />
          </template>
        </n-space>
      </SettingContainer>
    </n-drawer-content>
  </n-drawer>
</template>

然后我们在stores/app.ts中实现根据布局自动调整布局和风格列表

import type { LayoutType } from '~/config/layout-theme'
import { layoutThemeConfig } from '~/config/layout-theme'
export const useAppStore = defineStore('app', () => {
  const defaultTheme = import.meta.env.DEV ? layoutThemeConfig : useLayoutTheme()
  const layout = reactive(unref(defaultTheme))
  const visible = ref(false)
  const toggleVisible = (val: boolean) => {
    visible.value = val
  }

  const toggleCollapsed = (val: boolean) => {
    layout.collapsed = val
  }

  const updateLayout = (val: 'mix' | 'side' | 'top') => {
    layout.layout = val
  }

  const updateLayoutStyle = (val: 'light' | 'inverted') => {
    layout.layoutStyle = val
  }

  const layoutList = computed<LayoutType[]>(() => {
    return [
      {
        id: 'side',
        key: 'side',
        inverted: true,
        title: 'Side Menu Layout',
      },
      {
        id: 'top',
        key: 'top',
        title: 'Top Menu Layout',
      },
      {
        id: 'mix',
        key: 'mix',
        title: 'Mix Menu Layout',
      },
    ]
  })
  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 {
      updateLayoutStyle('light')
    }
    return list
  })
  return {
    layout,
    visible,
    layoutList,
    layoutStyleList,
    toggleVisible,
    toggleCollapsed,
    updateLayout,
    updateLayoutStyle,
  }
})

然后再base-layout/index.vue中配置如下:

<script lang="ts" setup>
  const { layout, visible, layoutList, layoutStyleList } = storeToRefs(appStore)
</script>

<template>
  <SettingDrawer
    v-model:layout-style="layout.layoutStyle"
    v-model:layout="layout.layout"
    :layout-list="layoutList"
    :layout-style-list="layoutStyleList"
  />
</template>

测试效果

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