mirror of
https://github.com/chansee97/nova-admin.git
synced 2025-04-06 03:57:54 +08:00
refactor(components): 二次封装e-icon
This commit is contained in:
parent
d5e46c3473
commit
d8b0fec8c8
19
src/components/EIcon.vue
Normal file
19
src/components/EIcon.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<Icon :icon="props.icon" class="inline-block" :width="props.size" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { Icon } from '@iconify/vue';
|
||||||
|
const props = defineProps({
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: 'icon-park-outline:game',
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 18,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
@ -1,25 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-layout has-sider class="wh-full">
|
<n-layout has-sider class="wh-full">
|
||||||
<n-layout-sider
|
<n-layout-sider bordered :collapsed="appStore.collapsed" :collapsed-width="64" collapse-mode="width">
|
||||||
bordered
|
<Logo />
|
||||||
show-trigger
|
<Menu />
|
||||||
:collapsed="collapsed"
|
|
||||||
:collapsed-width="64"
|
|
||||||
collapse-mode="width"
|
|
||||||
@collapse="collapsed = true"
|
|
||||||
@expand="collapsed = false"
|
|
||||||
>
|
|
||||||
<Logo :collapsed="collapsed" />
|
|
||||||
<n-menu
|
|
||||||
:collapsed="collapsed"
|
|
||||||
:collapsed-width="64"
|
|
||||||
:collapsed-icon-size="24"
|
|
||||||
:indent="20"
|
|
||||||
:options="menuOptions"
|
|
||||||
@update:value="handleClickMenu"
|
|
||||||
/>
|
|
||||||
</n-layout-sider>
|
</n-layout-sider>
|
||||||
|
|
||||||
<n-layout class="h-full bg-hex-f3f4f6" :native-scrollbar="false">
|
<n-layout class="h-full bg-hex-f3f4f6" :native-scrollbar="false">
|
||||||
<n-layout-header bordered class="h-60px flex-y-center">
|
<n-layout-header bordered class="h-60px flex-y-center">
|
||||||
<CollapaseButton />
|
<CollapaseButton />
|
||||||
@ -36,78 +20,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { MenuOption } from 'naive-ui';
|
import { useApp } from '@/store';
|
||||||
import { h, ref } from 'vue';
|
import { Breadcrumb, CollapaseButton, Menu, Logo } from '../components';
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { Icon } from '@iconify/vue';
|
|
||||||
import Logo from '../components/Logo.vue';
|
|
||||||
import Breadcrumb from '../components/Breadcrumb.vue';
|
|
||||||
import CollapaseButton from '../components/CollapaseButton.vue';
|
|
||||||
|
|
||||||
const router = useRouter();
|
const appStore = useApp();
|
||||||
const collapsed = ref(false);
|
|
||||||
|
|
||||||
function renderIcon(icon: string) {
|
|
||||||
return () => h(Icon, { icon });
|
|
||||||
}
|
|
||||||
// const activeKey = ref('');
|
|
||||||
const handleClickMenu = (key: string, _item: MenuOption) => {
|
|
||||||
router.push(key);
|
|
||||||
};
|
|
||||||
const menuOptions: MenuOption[] = [
|
|
||||||
{
|
|
||||||
label: 'test1',
|
|
||||||
key: '/test1',
|
|
||||||
icon: renderIcon('icon-park-outline:alarm'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'test2',
|
|
||||||
key: '/test2',
|
|
||||||
icon: renderIcon('icon-park-outline:alarm'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'test3',
|
|
||||||
key: '/test3',
|
|
||||||
icon: renderIcon('icon-park-outline:alarm'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '登录页',
|
|
||||||
key: '/login',
|
|
||||||
icon: renderIcon('icon-park-outline:alarm'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '舞,舞,舞',
|
|
||||||
key: 'dance-dance-dance',
|
|
||||||
icon: renderIcon('icon-park-outline:alarm'),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
label: '饮品',
|
|
||||||
key: 'beverage',
|
|
||||||
// icon: renderIcon(WineIcon),
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
label: '威士忌',
|
|
||||||
key: 'whisky',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '食物',
|
|
||||||
key: 'food',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
label: '三明治',
|
|
||||||
key: 'sandwich',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '过去增多,未来减少',
|
|
||||||
key: 'the-past-increases-the-future-recedes',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<n-breadcrumb>
|
<n-breadcrumb>
|
||||||
<n-breadcrumb-item class="align-middle">
|
<n-breadcrumb-item class="align-middle">
|
||||||
<Icon icon="icon-park-outline:home-two" class="inline-block" width="16" />
|
<e-icon icon="icon-park-outline:home-two" />
|
||||||
首页
|
首页
|
||||||
</n-breadcrumb-item>
|
</n-breadcrumb-item>
|
||||||
<n-breadcrumb-item v-for="(item, index) in routes" :key="index">
|
<n-breadcrumb-item v-for="(item, index) in routes" :key="index">
|
||||||
<Icon :icon="item.meta.icon" class="inline-block" width="18" />
|
<e-icon :icon="item.meta.icon" />
|
||||||
{{ item.meta.title }}
|
{{ item.meta.title }}
|
||||||
</n-breadcrumb-item>
|
</n-breadcrumb-item>
|
||||||
</n-breadcrumb>
|
</n-breadcrumb>
|
||||||
@ -17,16 +17,6 @@ import { useRouter } from 'vue-router';
|
|||||||
import { Icon } from '@iconify/vue';
|
import { Icon } from '@iconify/vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// const props = defineProps({
|
|
||||||
// title: {
|
|
||||||
// type: String,
|
|
||||||
// default: 'Logo2',
|
|
||||||
// },
|
|
||||||
// collapsed: {
|
|
||||||
// type: Boolean,
|
|
||||||
// default: false,
|
|
||||||
// },
|
|
||||||
// });
|
|
||||||
const routes = computed(() => {
|
const routes = computed(() => {
|
||||||
return router.currentRoute.value.matched.filter((item) => {
|
return router.currentRoute.value.matched.filter((item) => {
|
||||||
return item.meta.title;
|
return item.meta.title;
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="hover:bg-hex-F3F4F6 hover:shadow-inner h-full px-2 flex-center cursor-pointer">
|
<div
|
||||||
<Icon icon="icon-park-outline:music-list" class="inline-block" width="18" />
|
class="hover:bg-hex-F3F4F6 hover:shadow-inner h-full px-2 flex-center cursor-pointer"
|
||||||
|
@click="appStore.switchCollapse()"
|
||||||
|
>
|
||||||
|
<e-icon v-show="appStore.collapsed" icon="icon-park-outline:menu-unfold" />
|
||||||
|
<e-icon v-show="!appStore.collapsed" icon="icon-park-outline:menu-fold" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Icon } from '@iconify/vue';
|
import { useApp } from '@/store';
|
||||||
|
const appStore = useApp();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
85
src/layouts/components/Menu.vue
Normal file
85
src/layouts/components/Menu.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<n-menu
|
||||||
|
:collapsed="appStore.collapsed"
|
||||||
|
:collapsed-width="64"
|
||||||
|
:collapsed-icon-size="24"
|
||||||
|
:indent="20"
|
||||||
|
:options="menuOptions"
|
||||||
|
@update:value="handleClickMenu"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useApp } from '@/store';
|
||||||
|
import { Icon } from '@iconify/vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import { h } from 'vue';
|
||||||
|
import type { MenuOption } from 'naive-ui';
|
||||||
|
|
||||||
|
const appStore = useApp();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
function renderIcon(icon: string) {
|
||||||
|
return () => h(Icon, { icon });
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClickMenu = (key: string, _item: MenuOption) => {
|
||||||
|
router.push(key);
|
||||||
|
};
|
||||||
|
const menuOptions: MenuOption[] = [
|
||||||
|
{
|
||||||
|
label: 'test1',
|
||||||
|
key: '/test1',
|
||||||
|
icon: renderIcon('icon-park-outline:alarm'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'test2',
|
||||||
|
key: '/test2',
|
||||||
|
icon: renderIcon('icon-park-outline:tool'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'test3',
|
||||||
|
key: '/test3',
|
||||||
|
icon: renderIcon('icon-park-outline:pic'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '登录页',
|
||||||
|
key: '/login',
|
||||||
|
icon: renderIcon('icon-park-outline:save'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '舞,舞,舞',
|
||||||
|
key: 'dance-dance-dance',
|
||||||
|
icon: renderIcon('icon-park-outline:command'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: '饮品',
|
||||||
|
key: 'beverage',
|
||||||
|
// icon: renderIcon(WineIcon),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: '威士忌',
|
||||||
|
key: 'whisky',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '食物',
|
||||||
|
key: 'food',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: '三明治',
|
||||||
|
key: 'sandwich',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '过去增多,未来减少',
|
||||||
|
key: 'the-past-increases-the-future-recedes',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
6
src/layouts/components/index.ts
Normal file
6
src/layouts/components/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import Breadcrumb from './Breadcrumb.vue';
|
||||||
|
import CollapaseButton from './CollapaseButton.vue';
|
||||||
|
import Logo from './Logo.vue';
|
||||||
|
import Menu from './Menu.vue';
|
||||||
|
|
||||||
|
export { Breadcrumb, CollapaseButton, Menu, Logo };
|
@ -1,21 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="h-60px text-2xl flex-center">
|
<div class="h-60px text-2xl flex-center overflow-hidden">
|
||||||
<SvgIcon name="logo" class="w-9 h-9" />
|
<SvgIcon name="logo" class="w-9 h-9" />
|
||||||
<span v-show="!props.collapsed" class="mx-5">{{ props.title }}</span>
|
<div v-show="!appStore.collapsed" class="mx-5">{{ appStore.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
import { useApp } from '@/store';
|
||||||
title: {
|
const appStore = useApp();
|
||||||
type: String,
|
|
||||||
default: 'Logo2',
|
|
||||||
},
|
|
||||||
collapsed: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
@ -5,3 +5,4 @@ export function setupStore(app: App) {
|
|||||||
const store = createPinia();
|
const store = createPinia();
|
||||||
app.use(store);
|
app.use(store);
|
||||||
}
|
}
|
||||||
|
export * from './modules';
|
||||||
|
15
src/store/modules/app.ts
Normal file
15
src/store/modules/app.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useApp = defineStore('app-store', {
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
collapsed: false,
|
||||||
|
title: import.meta.env.VITE_APP_TITLE,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
switchCollapse() {
|
||||||
|
this.collapsed = !this.collapsed;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
9
src/store/modules/auth.ts
Normal file
9
src/store/modules/auth.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useAuth = defineStore('auth-store', {
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
name: '张三',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
@ -1 +1,2 @@
|
|||||||
export * from './user';
|
export * from './user';
|
||||||
|
export * from './app';
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStore } from '@/store/modules';
|
import { useStore } from '@/store';
|
||||||
|
|
||||||
const userStore = useStore();
|
const userStore = useStore();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user