Vue2
<!-- 左侧导航组件 -->
<!-- 使用说明:<side-bar></side-bar> -->
<template>
<div class="sidebar_wrap">
<!-- <div class="wrap_title">
<img src="@/assets/images/logo.png" alt />
<div>张家湾数字管理平台</div>
</div> -->
<div class="wrap_catalog">
<el-menu :default-active="'/'+NavActive" :unique-opened="isUnique" :router="isRouter" mode="vertical"
ref="menu">
<!-- 一级菜单 -->
<template v-for="(item,index) in navData">
<el-submenu v-if="item.children && item.children.length" :index="item.router" :key="index"
ref="elMenu" class="list_one" @open="open">
<template slot="title">
<div @click="clickStatus($event,item)">
<img :src="require('../assets/images/' +item.icon_none + '.png')" class="imgs1"
v-if="item.status === '0'" />
<span>{{item.name}}</span>
</div>
</template>
<!-- 二级菜单 -->
<template v-for="itemChild in item.children">
<el-menu-item :index="itemChild.router" :key="itemChild.router">
<span slot="title" class='submenu'>{{itemChild.name}}</span>
</el-menu-item>
</template>
</el-submenu>
<el-menu-item v-else :index="item.router" :key="item.router" @open="open" ref="elMenu"
class="list_two">
<div @click="clickStatus($event,item)">
<img :src="require('../assets/images/' +item.icon_none + '.png')" class="imgs1"
v-if="item.status === '0'" />
<span slot="title">{{item.name}}</span>
</div>
</el-menu-item>
</template>
</el-menu>
</div>
</div>
</template>
<script>
import {studentsList} from "../assets/js/studentsList";
import {parentList} from '../assets/js/parentList'
import {teacherList} from '../assets/js/teacherList'
export default {
name: "sidebar",
data() {
return {
isUnique: true,
isRouter: true,
navData: [],
NavActive: "",
};
},
beforeMount() {
this.getActiveNav();
},
watch: {
//监听路由变化
$route(index) {
// console.log('sideBarRouter',index)
let path = index.path.substr(1);
this.handleSelect(path);
},
},
created() {
// this.navData = JSON.parse(localStorage.menus);
},
mounted() {
let userVal = sessionStorage.getItem("userVal");
if(userVal==0){
this.navData = studentsList.list;
this.$router.push({path:'/studentHome'})
}else if(userVal==1){
this.navData = parentList.list;
this.$router.push({path:'/parentHome'})
}else if(userVal==2){
this.navData = teacherList.list
this.$router.push({path:'/teacherHome'})
}
// console.log(sessionStorage.getItem("isGarden") === "0");
// console.log(sessionStorage.getItem("isGarden") === "1");
// // isGarden === 0 为园区端;isGarden === 1 为企业端
// if (sessionStorage.getItem("isGarden") === "0") {
// this.navData = navDataList.list;
// } else if (sessionStorage.getItem("isGarden") === "1") {
// this.navData = navdataa.list;
// }
},
methods: {
getActiveNav() {
let currentUrl = window.location.href;
this.NavActive = currentUrl.split("/").pop();
},
//监听路由的变化,对应菜单高亮显示
handleSelect(index) {
this.NavActive = index;
},
clickStatus(e, item) {
// console.log(e,item)
// console.log(this.$refs.elMenu)
// this.$refs.elMenu.map((item1) => {
// console.log(item1.$el)
// // if(item1.active === false){
// // }
// })
},
open() {
console.log("1");
},
},
};
</script>
<style scoped lang="less">
.sidebar_wrap {
width: 1.4583rem;
height: 100%;
// background: #870000;
background: #fff;
overflow-y: auto;
overflow-x: hidden;
.wrap_title {
display: flex;
align-items: center;
justify-content: center;
font-size: 0.1111rem;
color: #fff;
height: 0.5556rem;
img {
width: 0.2778rem;
height: 0.1528rem;
margin-right: 0.0764rem;
}
}
.wrap_catalog {
/deep/ .el-menu {
border-right: none;
// background-color: #870000;
background-color: #fff;
width: 1.4583rem;
li {
padding: 0 !important;
}
.el-menu-item {
height: 0.3056rem;
line-height: 0.3056rem;
font-size: 0.1111rem;
color: #0E151E;
// border-bottom: 0.0069rem solid #a43d3d;
}
.el-submenu__title {
height: 0.3056rem;
line-height: 0.3056rem;
font-size: 0.1111rem;
// color: #0E151E;
// border-bottom: 0.0069rem solid #a43d3d;
}
.el-submenu__icon-arrow {
display: none;
}
.el-menu-item.is-active {
width: 1.4583rem;
height: 0.3056rem;
color: #FFFFFF;
padding-left: 0.6944rem;
// background: #B40024;
// background: url("../assets/new_images/xuanzhong.png") no-repeat;
background-color: #D9221A;
// background-position: 0.0694rem 0.0486rem;
}
.el-menu-item:hover {
// background: #B40024;
background-color: #D9221A;
color: #fff;
// background: url("../assets/new_images/xuanzhong.png") no-repeat;
// background-position: 0.0694rem 0.0486rem;
}
.el-submenu.is-active.is-opened {
// background: #B40024;
// background: url("../assets/new_images/xuanzhong.png") no-repeat;
// background-position: 0.0694rem 0.0486rem;
background-color: #D9221A;
color: #fff;
.el-menu-item.is-active {
// background: #A20A1E;
background-color: #D9221A;
color: #fff;
}
.el-menu-item:hover {
// background: #A20A1E;
background-color: #D9221A;
color: #fff;
}
}
.el-submenu:hover {
.el-menu-item:hover {
// background: #A20A1E;
background-color: #D9221A;
color: #fff;
}
}
.el-submenu__title:hover {
// background: #B40024;
// background: url("../assets/new_images/xuanzhong.png") no-repeat;
// background-position: 0.0694rem 0.0486rem;
background-color: #D9221A;
color: #fff;
.el-menu-item:hover {
// background: #A20A1E;
background-color: #D9221A;
color: #fff;
}
}
.el-submenu.is-opened:hover {
// background: #B40024;
// background: url("../assets/new_images/xuanzhong.png") no-repeat;
// background-position: 0.0694rem 0.0486rem;
background-color: #D9221A;
color: #fff;
.el-menu-item:hover {
// background: #A20A1E;
background-color: #D9221A;
}
}
.imgs1 {
width: 0.1389rem;
height: 0.1389rem;
margin-right: 0.0347rem;
}
.submenu {
font-family: 'PingFang-Regular';
}
}
.list_one:last-child {
// border-bottom: 0.0069rem solid #870000;
/deep/ .el-menu-item:last-child {
// border-bottom: 0.0069rem solid #870000;
}
}
.list_two:last-child {
// border-bottom: 0.0069rem solid #870000;
}
}
}
</style>
以上是封装的侧边栏组件,需要搭配js文件使用,格式如下:
(px to rem 比例是144 需要使用px可以转回来)
// 导航栏信息
// 一级导航index要与其子代(二级)导航第一个index相同
// name: 菜单要显示的名字
// index: 导航地址(router中的名字)
// img: 图标名字(用class定义)
// children: 迭代子代导航、参数如上
// 教师端
export const teacherList = {
"list": [
{
"name": "健康测评",
"name_en": "teacherHome",
"router": "/teacherHome",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},{
"name": "心理测评",
"name_en": "psychometrics",
"router": "/psychometrics",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},{
"name": "教学资源",
"name_en": "teachResources",
"router": "/teachResources",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},{
"name": "在线研修",
"name_en": "autonomouslyStudy",
"router": "/autonomouslyStudy",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [
{
"name": "自主学习",
"name_en": "autonomouslyStudy",
"router": "/autonomouslyStudy",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},
{
"name": "教师调研",
"name_en": "teacherResearch",
"router": "/teacherResearch",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},
{
"name": "直播培训",
"name_en": "liveTraining",
"router": "/liveTraining",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},
{
"name": "在线阅读",
"name_en": "onlineReading",
"router": "/onlineReading",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},
{
"name": "课程研究",
"name_en": "projectResearch",
"router": "/projectResearch",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},
{
"name": "展示交流",
"name_en": "displayCommunication",
"router": "/displayCommunication",
"icon_none": "shouyeIcon_255",
"icon_block": "shouyeIcon_255",
"status": '0',
"children": [],
},
],
},
]
}
Vue3 ====components===sidebar文件夹===sider.vue sidebarItem.vue
sider.vue
<script lang="ts" setup>
// sidebarItem 项组件
import SideBarItem from './sidebarItem.vue';
import { useRouter } from 'vue-router';
// 拿到路由列表,过滤我们不想要的
const router = useRouter();
const routerList = router.getRoutes().filter((v) => v.meta && v.meta.isShow);
</script>
<template>
<div class="sidebar">
<!-- 项目名称及logo -->
<div class="sidebar-logo flex-center">
<svg-icon icon-class="logo" />
<span>VitalityAdmin</span>
</div>
<!-- 导航菜单 -->
<el-menu
active-text-color="#fff"
background-color="#001529"
:default-active="$route.path"
text-color="#999"
:unique-opened="true"
router>
<!-- 引入子组件 -->
<SideBarItem :routerList="routerList" />
</el-menu>
<!-- active-text-color:当前菜单项被选中时,字体的颜色 -->
<!-- background-color:这个menu菜单的背景色 -->
<!-- default-active: 当前激活菜单的 index -->
<!-- text-color:菜单项字体颜色 -->
<!-- unique-opened:unique-opened 是否只保持一个子菜单的展开 -->
<!-- router:是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转 -->
</div>
</template>
<style lang="scss" scoped>
.sidebar {
height: 100%;
.sidebar-logo {
height: 48px;
background-color: #002140;
color: #fff;
font-weight: 700;
line-height: 48px;
text-align: center;
font-size: 20px;
}
.el-menu {
height: calc(100% - 48px);
border-right: 0;
overflow: auto;
}
}
</style>
sidebarItem.vue
<script setup lang="ts">
import { RouteRecordRaw } from 'vue-router';
// 做类型限制,解决ts类型报错
type CustomRouteRecordRaw = RouteRecordRaw & {
meta: {
isShow?: boolean;
};
};
const props = defineProps({
// 拿到父组件传递过来的路由列表进行渲染
routerList: {
type: Array as () => CustomRouteRecordRaw[],
required: true
}
});
</script>
<template>
<template v-for="item in props.routerList" :key="item.path">
<!-- 当该菜单项有子菜单时 -->
<el-sub-menu :index="item.path" v-if="item.children && item.children.length > 0">
<template #title v-if="item.meta.icon">
<!-- 菜单项图标,我此处用的是全局封装的 svg组件 -->
<el-icon><svg-icon :icon-class="item.meta.icon" /></el-icon>
<!-- 菜单项名称,在路由中定义好 -->
<span>{{ item.meta.title }}</span>
</template>
<!-- 若路由中未定义菜单项icon,则仅展示名称--(我的仅一级菜单有图标) -->
<template #title v-else>{{ item.meta.title }}</template>
<!-- 递归遍历-自己调用自己(核心代码) -->
<sidebarItem :routerList="( item.children as CustomRouteRecordRaw[])" />
</el-sub-menu>
<!-- 当前菜单项无子菜单 -->
<el-menu-item :index="item.path" v-else>
<!-- 与上面注释大致相同,不多做额外注释 -->
<template v-if="item.meta.icon">
<el-icon><svg-icon :icon-class="item.meta.icon" /></el-icon>
<span>{{ item.meta.title }}</span>
</template>
<template v-else>
{{ item.meta.title }}
</template>
</el-menu-item>
</template>
</template>
<style scoped lang="scss">
.is-active {
background: #409eff;
font-weight: 700;
}
.el-menu-item {
&:hover {
color: #fff;
font-weight: 700;
}
}
.el-menu--collapse {
.el-menu-item {
justify-content: center;
}
}
// 下列代码是用于兼容horizontal所写,酌情删或留
.el-menu--horizontal {
.el-menu-item.is-active {
background-color: transparent !important;
border-bottom: 2px solid #409eff !important;
.el-icon,
span {
color: #409eff !important;
}
}
.el-sub-menu.is-active {
.el-sub-menu__title {
border: 0 !important;
}
.el-icon,
span {
color: #409eff !important;
}
}
}
</style>