基于vue3.0和element-plus的组件库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

157 lines
4.1 KiB

<template>
<div class="menu-container">
<el-menu
:default-active="active"
router
:mode="mode"
:class="mode"
:text-color="state.style.menuColor"
:background-color="mode == 'horizontal' ? state.style.headBg : state.style.menuBg"
:active-text-color="state.style.menuActiveColor"
:size="state.size.size"
>
<div class="title" v-if="title">
<el-image class="logo" v-if="logo" :src="logo" fit="fit" />
{{ title || t("title") }}
</div>
<template v-for="menu in data || state.menus">
<template v-if="menu.children && menu.children.length > 0">
<el-sub-menu :index="getPath(menu)" :key="menu.path">
<template #title>
<component class="icon" :is="menu.icon || state.style.menuDefaultIcon"> </component>
<span>{{ menu.title || t(menu.i18n) }}</span>
</template>
<el-menu-item v-for="child in menu.children" :index="getPath(child)" :router="router">
<component
class="icon"
:width="getters.menuIconSize"
:height="getters.menuIconSize"
:is="child.icon || state.style.menuDefaultIcon"
>
</component>
{{ child.title || t(child.i18n) }}
</el-menu-item>
</el-sub-menu>
</template>
<template v-else>
<el-menu-item :index="getPath(menu)" :key="menu.path" :router="router">
<component class="icon" :is="menu.icon || state.style.menuDefaultIcon"></component>
<span>{{ menu.title || t(menu.i18n) }}</span>
</el-menu-item>
</template>
</template>
</el-menu>
<div class="menu-footer">
<slot name="footer" />
</div>
</div>
</template>
<script setup lang="ts">
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { ref, onMounted, reactive } from "vue";
import { useI18n } from "vue3-i18n";
const { t } = useI18n();
const { state, getters } = useStore();
const props = defineProps({
mode: {
type: String,
default: "vertical",
},
data: {
type: Array<any>(),
default: null,
},
logo: {
type: String,
default: null,
},
title: {
type: String,
default: null,
},
});
const { VITE_APP_VERSION, VITE_GIT_HASH } = import.meta.env;
const style = reactive({ "margin-right": "10px", width: getters.menuIconSize, height: getters.menuIconSize });
const router = useRouter();
const getPath = (menu) => {
const prefix = menu.path.startsWith("/") ? "" : "/";
return prefix + menu.path;
};
const active = ref("");
onMounted(() => {
setTimeout(() => {
active.value = router.currentRoute.value.path.substring(1);
}, 200);
router.push(active.value);
});
</script>
<style scoped lang="scss">
.menu-container {
overflow: hidden;
height: 100%;
display: flex;
flex-direction: column;
.el-menu {
flex: 1;
}
.menu-footer {
background-color: v-bind("state.style.menuBg");
color: v-bind("state.style.menuColor");
font-size: 10px;
display: flex;
flex-direction: column;
align-items: center;
}
}
.title {
height: v-bind("state.size.headHeight");
width: v-bind("state.size.asideWidth");
text-align: center;
font-size: v-bind("state.size.titleSize");
line-height: v-bind("state.size.headHeight");
font-weight: bold;
color: v-bind("state.style.menuColor");
}
.horizontal {
padding-top: 1px;
height: v-bind("state.size.headHeight");
border: none;
// display: inline-flex;
}
.vertical {
padding-top: 1px;
// height: v-bind('state.size.mainHeight');
height: 100%;
border: none;
}
.icon {
margin-right: 10px;
width: v-bind("state.size.menuIconSize");
height: v-bind("state.size.menuIconSize");
}
.el-menu-item.is-active {
background-color: v-bind("state.style.menuActiveBg");
}
.vertical .el-sub-menu,
.vertical .el-menu-item {
min-width: v-bind("state.size.asideWidth") !important;
font-size: v-bind("state.size.fontSize") !important;
}
.horizontal .el-sub-menu,
.horizontal .el-menu-item {
font-size: v-bind("state.size.fontSize") !important;
}
</style>