目的
项目分为全局路由如登录页面,404页面之类的和由侧边栏menu控制跳转的子路由页面主要是业务页面。页面子页面放入views文件夹下,将自动读入注册成route,配置文件主要用于生成树形menu侧边栏。建议配合项目结构进行阅读效果更佳
效果
项目结构
子页面配置文件
将根据以下配置文件生成树形menu导航栏
export default [
{
url: "/page1",
meta: {
title: '页面1', requiresAuth: false },
children: [
{
url: "/page2",
meta: {
requiresAuth: false,
title: "页面2"
},
children: [
{
url: "/page3",
meta: {
requiresAuth: false,
title: "页面3"
}
},
],
},
],
},
{
url: "/page4",
meta: {
title: '页面4', requiresAuth: false }
}
]
全局页面配置文件
export default [
{
url: "/login",
meta: {
title: '登录', requiresAuth: false }
},
]
侧边栏模板组件
sideBar组件
<template>
<div class="side-bar-wrapper" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave">
<el-aside class="index-aside" :width="isSideBarExpand?'65px':'150px'">
<div class="title_banner"></div>
<el-menu
class="aside-menu"
:collapse="isSideBarExpand"
ref="sideBar"
:default-active="onRoutes"
text-color="#a5a5a5"
active-text-color="#00c1de"
background-color="#414549"
unique-opened
menu-trigger="click"
:collapse-transition="collapseTransition"
>
<template v-for="(item) in menuList">
<el-menu-item
v-if="!item.list"
:index="item.route"
:key="item.route"
@click="barHref(item.route)"
>
<icon-svg
:icon-class="item.icon"
:class="{
'avtive_bar_icon':item.route == onRoutes,
'bar_icon':item.route != onRoutes
}"
/>
<span slot="title" class="bar_title">{
{
item.title}}</span>
</el-menu-item>
<TreeMenu :key="item.route+'s'" v-if="item.list" :item="item"></TreeMenu>
</template>
</el-menu>
</el-aside>
</div>
</template>
<script>
import page from "@/config/router/pages.js";
import TreeMenu from "./menu";
export default {
name: "sideBar",
created() {
this.getCachePage();
},
components: {
TreeMenu },
data() {
return {
isCollapse: false,
isSideBarExpand: true,
collapseTransition: false,
menuList: []
};
},
methods: {
async getCachePage() {
this.menuList = this.creatMenu(page);
},
/*
保存被打开的侧边栏的状态
*/
onMouseEnter() {
this.isSideBarExpand = false;
let menuRoute = "";
this.menuList.forEach(x => {
if (x.list && x.list.length > 0) {
if (
x.list.find(y => {
return y.route === this.onRoutes;
})
) {
menuRoute = x.route;
}
}
});
if (menuRoute) this.$refs.sideBar.open(menuRoute);
},
onMouseLeave() {
this.isSideBarExpand = true;
},
showSideBar() {
this.isCollapse = !this.isCollapse;
},
creatMenu(list) {
var menuList = [];
list.forEach(s => {
let menu = {
title: s.meta.title,
icon: s.url.replace("/", ""),
index: s.url.replace("/", ""),
route: s.url,
list:
s.children && s.children.length > 0
? this.creatMenu(s.children)
: undefined
};
menuList.push(menu);
});
return menuList;
},
barHref(s) {
if(s==this.onRoutes)return
this.$router.push({
path: s });
}
},
computed: {
onRoutes() {
return this.$route.path;
}
}
};
</script>
<style lang="scss" >
.side-bar-wrapper {
height: 100%;
z-index: 20;
}
.title_banner {
width: 100%;
height: 50px;
}
.side-bar-wrapper .index-aside {
overflow: hidden;
position: absolute;
left: 0;
top: 0;
bottom: 0;
z-index: 20;
// padding-top: 20px;
background: #414549;
-webkit-transition: width 0.3s;
transition: width 0.3s;
.el-menu {
border-right: none;
.el-menu-item {
// padding-left: 20px !important;
}
}
}
.side-bar-wrapper .index-aside .aside-menu {
height: 100%;
}
.side-bar-wrapper .index-aside .aside-menu .nav-icon {
width: 20px;
height: 20px;
}
.side-bar-wrapper .index-aside .el-menu {
overflow: hidden;
}
.bar_icon {
color: #fff;
}
.avtive_bar_icon {
color: #00c1de;
}
.bar_title {
margin-left: 5px;
}
</style>
menu组件
主要用于树形嵌套结构
<template>
<el-submenu
v-if="item.title&&item.list"
:index="item.route"
:key="item.route"
:show-timeout="0"
:hide-timeout="0"
>
<template slot="title">
<div>
<icon-svg
:icon-class="item.icon"
:class="{
'avtive_bar_icon':inParentPage(item.list,onRoutes),
'bar_icon':!inParentPage(item.list,onRoutes)
}"
/>
<span slot="title" style="margin-left:3px">{
{
item.title}}</span>
</div>
</template>
<template v-for="(it) in item.list">
<el-menu-item v-if="!it.list" :index="it.route" :key="it.route" @click="barHref(it.route)">
<icon-svg
:icon-class="it.icon"
:class="{
'avtive_bar_icon':it.route == onRoutes,
'bar_icon':it.route != onRoutes
}"
/>
<span slot="title" class="bar_title">{
{
it.title}}</span>
</el-menu-item>
<TreeMenu :key="it.route+'s'" v-if="it.list" :item="it"></TreeMenu>
</template>
</el-submenu>
</template>
<script>
export default {
props: ["item"],
name: "TreeMenu",
methods: {
barHref(s) {
if(s==this.onRoutes)return
this.$router.push({
path: s });
},
inParentPage(list,page){
let flag = false
function loop(pages,p){
for(let i = 0 ;i<pages.length;i++){
if(pages[i].route==p){
flag = true;
break
}
if(pages[i].list){
loop(pages[i].list,page)
}
}
}
loop(list,page)
return flag
},
},
computed: {
onRoutes() {
return this.$route.path;
}
}
};
</script>
<style scoped lang='scss'>
.bar_icon {
color: #fff;
}
.avtive_bar_icon {
color: #00c1de;
}
.bar_title {
margin-left: 5px;
}
</style>
结合Element 布局组件,生成主页面
<template>
<el-container class="content">
<side-bar></side-bar>
<el-container class="main-container">
<el-header style="height:50px">
<common-header ref="commomHeader"></common-header>
</el-header>
<el-main>
<router-view :key="key"></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
import sideBar from "./sideBar.vue";
import commonHeader from "./commonHeader.vue";
export default {
components: {
sideBar, commonHeader },
computed: {
key() {
return this.$route.name !== undefined
? this.$route.name + +new Date()
: this.$route + +new Date();
}
}
};
</script>
<style lang='scss'>
.el-container {
position: relative;
}
.el-header {
padding: 0px;
}
.main-container{
margin-left: 65px;
}
</style>
vue router 配置,读取页面配置文件自动注册路由
import page from './pages.js'
import globalPage from './globalPages.js'
import Router from 'vue-router'
const vueRouter = new Router({
mode: 'history',
routes: [...getRouteList(globalPage)]
})
vueRouter.addRoutes(
[{
path: '/',
name: 'index',
component: resolve => require(["@/globalViews/main/main.vue"], resolve),
children: [...getRouteList([...page])],
// redirect: page[0].url // 默认index重定向到home页面
}
]
)
// 全局钩子,单独页面钩子在配置项单独设置
vueRouter.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !localStorage.getItem("Token")) {
console.warn('没有权限,跳转到登录')
next('/login')
} else {
next()
}
})
// 根据配置生成route对象集合
function getRouteList(routes) {
let res = []
let hander = function (list) {
list.forEach((s) => {
if (s.children) {
hander(s.children)
}
if (s.url) {
let route = {
path: s.url,
component: resolve => require(["@/views" + s.url + s.url + ".vue"], resolve),
name: s.url.replace('/', ''),
meta: s.meta
}
res.push(route)
}
})
}
hander(routes)
// console.log(res)
return res
}
export default vueRouter;
将Router配置注入Vue构造
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import router from '@/config/router/index'
Vue.config.productionTip = false
Vue.use(VueRouter)
new Vue({
router,
render: h => h(App),
}).$mount('#app')
总结
还是react清晰好使
https://blog.csdn.net/weixin_39168678/article/details/107315893