1.前言
- 路由分为静态路由和动态路由,静态路由由前端直接写死,优点是简单方便,但是权限控制有漏洞,用户可以输入目标url强行访问没有权限的页面,而动态路由就可以避免这个问题,但是需要和后端数据对接,一般接口返回的数据需要转换后才能进行注册,注册后的页面才能进行访问,这个就避免了强行访问的问题
2.页面分类
- 页面分为3种:固定页面,管理页面(带左侧和顶部的导航,主内容取才是真正的内容),和全屏页面
- 固定页面:登录页,修改密码页面等,无需权限就能访问的页面
- 管理页面:使用嵌套路由进行渲染,分为两层,第一层统一渲染布局组件(左侧和顶部的导航),第二次才渲染真正的页面组件,其中第一层路由是虚的,本身没有实质内容,他只能强制性重定向它的一个子路由
- 全屏页面:使用一级路由进行注册,直接渲染该页面组件,一般不做权限管理
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const Layout = () => import('@/layout/index.vue')
const Not_found = () => import('@/views/404.vue')
export const constantRouterMap = [
{
path: '/', component: Layout, redirect: '/dashboard' ,
meta: {
},
children: [
{
path: 'dashboard', name: 'dashboard', component: () => import('@/views/dashboard/index.vue'),
meta: {
},
}
]
},
{
path: '/login', name: 'login', component: () => import('@/views/login/index.vue'),
meta: {
needLogin: false,
}
},
]
const router = new VueRouter({
routes: [
...constantRouterMap
]
})
export default router
- 注意:左侧和顶部的导航是公共组件,可以有其他处理方式进行条件渲染,但是不建议。例如在fasatdmin中在url后面通过传参?tab=1来控制渲染,有这个参数,则渲染左侧和顶部的导航,没有这个参数,则全屏渲染页面。但是在vue中会引发其他问题,首先tab参数不好挂载,因为url路径使用的是hash,跟传统的网页url不一样,解析这个tab参数需要特殊处理,其次也是最重要的,路由跳转时,会覆盖整个hash的值,导致这个tab参数丢失,除非又要特殊处理,但是这样的话就不值当了
3.动态路由
- 动态路由:调接口从服务器拿到可访问的页面列表进行动态路由注册
- 全屏页面:调用addRoute()方法,需要传入路由路径,路由名称,代码文件路径
addPage(){
this.$router.addRoute({
path: '/newPage',
name: 'newPage',
component: () => import('./views/newPage.vue')
})
}
- 管理页面:调用addRoute()方法,除了需要传入路由路径,路由名称,代码文件路径,还需要父级路由的名称
addChildPage(){
this.$router.addRoute('parentPage',{
path: 'newPage',
name: 'newPage',
component: () => import('./views/newPage.vue')
})
}
4.菜单与路由
- 一般通过权限管理来控制可访问的页面,路由规则和菜单展示他们共用一套数据
- 每个权限节点都需要以下字段:名称,路径,子节点,是否全屏,路径可以将路由路径和文件路径进行统一
- 菜单渲染需要的是树形节点的数据,而路由注册需要一维数组的数据,可分开进行处理
- 注册路由时,需要移除菜单目录节点,只留下页面节点
- 通过 是否全屏 这个节点来控制路由的注册是一级路由还是嵌套路由,注册嵌套路由时,自动裁剪当前路径作为路由的父节点,并自动注册此父节点路由,接着才注册嵌套路由
- 一级路由要设置name属性,以便添加嵌套路由,嵌套路由可以不设置name属性
<template>
<div id="app">
<router-view />
</div>
</template>
<script>
export default {
data() {
return {
whiteList: ['/login'],
meneList: []
}
},
watch: {
'$route.path': {
immediate: true,
handler: function(newVal){
if(!this.whiteList.includes(newVal) && this.meneList.length == 0){
this.getMenuList()
}
}
}
},
methods: {
getMenuList(){
this.meneList = [
{
id: 1,
title: "常用分类",
path: "/category/index",
fullView: 1,
},
{
id: 2,
title: "供应商管理",
path: "/supplier/index",
fullView: 1,
},
{
id: 3,
title: "物料分类",
path: "/material/category",
fullView: 0,
},
{
id: 4,
title: "物料档案",
path: "/material/archives",
fullView: 0,
}
]
this.initRouter()
},
initRouter(){
var rootPath = "./views"
this.meneList.forEach(item=>{
if(item.fullView == 1){
this.$router.addRoute({
path: item.path,
component: () => import(`${rootPath}${item.path}`)
})
}else{
var name = this.getParentName(item.path)
var allRoutes = this.$router.getRoutes()
var hasRegister = allRoutes.some(item=>{
return item.name == name
})
if(!hasRegister){
this.$router.addRoute({
path: '/' + name,
name: name,
component: () => import('./layout/index.vue')
})
}
this.$router.addRoute(name, {
path: item.path,
component: () => import(`${rootPath}${item.path}`)
})
}
})
},
getParentName(path){
var list = path.split('/').filter(item=>{
return item
})
return list[0]
},
}
}
</script>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了