下面介绍在实际项目中使用vue-router,整体规划设计
1. 规划内容
(1)核心的几个关键路由:登录页面,主页,错误页面。
(2)页面访问控制:有些页面不需要做登录控制
(3)动态路由:模块菜单有一部分是数据库配置的,因此除了固定路由外,有一部分是动态添加的路由
2. 详细设计
2.1 全局路由
全局路由指独立的,不需要验证是已登录的页面,不需要用到导航卫士,不需要使用嵌入Main框架:比如登录页,错误页,外部系统调用的页面(通过签名授权)
// 全局路由(无需嵌套上左右整体布局)
const globalRoutes = [
{ path: '/404', component: _import('common/404'), name: '404', meta: { title: '404未找到' } },
{ path: '/login', component: _import('common/Login'), name: 'login', meta: { title: '登录' } },
{ path: '/', component: _import('common/Login'), name: 'first', meta: { title: '登录' } },
{ path: '/scm2erp/consignmentPurchaseInvoice', component: _import('modules/erp/scm_settlement/consignment_purchase_invoice/ConsignmentPurchaseInvoice'), name: 'consignmentPurchaseInvoice', meta: {title: '代销买入发票'}},
{ path: '/scm2erp/dxInputInvoice', component: _import('modules/erp/scm_settlement/consignment_purchase_invoice/DxInputInvoice'), name: 'dxInputInvoice', meta: {title: '代销录入发票'}},
]
2.2 Main路由
(1)路由设计
Main路由就是登录后进入的首页,在这个首页里面同时 (同级) 展示多个组件,比如有MainNavbar (顶部), MainSidebar (侧导航) 和 MainContent (主内容) 。其中MainNavbar和MainSidebar是常规组件。MainContent是嵌套视图组件【Main的子组件】,所有页面显示在其中(含有路由的出口)。Main本身也是一个视图组件。
<template v-if="!loading">
<main-navbar />
<main-sidebar />
<div class="site-content__wrapper" :style="{ 'min-height': documentClientHeight + 'px' }">
<main-content v-if="!$store.state.common.contentIsNeedRefresh" />
</div>
</template>
// 引入视图组件
import MainNavbar from './MainNavbar'
import MainSidebar from './MainSidebar'
import MainContent from './MainContent'
components: {
MainNavbar,
MainSidebar,
MainContent
},
因此设计成嵌套路由
// 主入口路由(需嵌套上左右整体布局)
const mainRoutes = {
path: '/',
component: _import('Main'),
name: 'main',
redirect: { name: 'home' },
meta: { title: '主入口整体布局' },
// 固定路由
children: [
{ path: '/home', component: _import('common/Home'), name: 'home', meta: { title: '首页' } },
{ path: '/theme', component: _import('common/Theme'), name: 'theme', meta: { title: '主题' } },
{ path: '/supplier_settlement-OutAccountAudit', component: _import('modules/erp/sup_settlement/OutAccountAudit'), name: 'supplier_settlement-OutAccountAudit', meta: { title: '供应商出账数据稽核', isTab: true } }
]
}
在Main主路由中的所有页面的嵌套路由分两种,一种是如上的固定路由,不属于菜单,不通过数据库配置。
另外一种是动态路由,如通过数据库配置的菜单,因此需要动态添加路由:
//路由规则有 name,并且已经存在一个与之相同的名字,则会覆盖它。因此另外取一个名字
mainRoutes.name = 'main-dynamic'
mainRoutes.children = routes
router.addRoutes([
mainRoutes,
{ path: '*', redirect: { name: '404' } }
])
// 为了避免刷新后清空,需要本地先存
sessionStorage.setItem('dynamicMenuRoutes', JSON.stringify(mainRoutes.children || '[]'))
(2)访问控制
访问Main路由之前,验证是否已经登录成功,因此Main路由这里使用路由独享的守卫,如:
beforeEnter (to, from, next) {
let token = Vue.cookie.get('token')
if (!token || !/\S/.test(token)) {
clearLoginInfo()
next({ name: 'login' })
}
next()
}
2.3 全局守卫
访问路由前,如果请求的路径不是全局路由,并且没有添加动态路由,需要重新加载路由后,继续访问,目的解决刷新问题导致动态路由丢失。
router.beforeEach((to, from, next) => {
if (router.options.isAddDynamicMenuRoutes || fnCurrentRouteType(to, globalRoutes) === 'global') {
next()
} else {
http({
url: http.adornUrl('/sys/menu/nav'),
method: 'get',
params: http.adornParams()
}).then(({ data }) => {
if (data && data.code === 0) {
fnAddDynamicMenuRoutes(data.menuList)
router.options.isAddDynamicMenuRoutes = true
sessionStorage.setItem('menuList', JSON.stringify(data.menuList || '[]'))
sessionStorage.setItem('permissions', JSON.stringify(data.permissions || '[]'))
next({ ...to, replace: true })
} else {
sessionStorage.setItem('menuList', '[]')
sessionStorage.setItem('permissions', '[]')
next()
}
}).catch((e) => {
console.log(`%c${e} 请求菜单列表和权限失败,跳转至登录页!!`, 'color:blue')
router.push({ name: 'login' })
})
}
})
3. 其它设计
3.1 根路径匹配多个路由
登录页面要使用根路径,Main路由也使用根路径,目的为是以 / 开头的嵌套路径会被当作根路径。 充分的使用嵌套组件而无须设置嵌套的路径。由于同一个路径可以匹配多个路由,所以是可以实现的,同时要把登录页面路由放在Main路由前面。当路径匹配到多个路由时,优选匹配前面的。
3.2 匹配任意路径
对应输入错误地址时,我们不希望显示404,能够显示相应错误页面。因此路由最后面添加一个对于所有路径都能匹配一个的路由。当匹配不到路由,就匹配错误页面路由。
router.addRoutes([
mainRoutes,
{ path: '*', redirect: { name: '404' } }
])
网友评论