vue 动态路由、动态加载组件、动态生成页面
- 相信很多做后端管理系统的同学,都会有这样的需求,那就是动态加载菜单,动态路由,甚至是动态生成页面。下面将一一介绍这些功能
动态路由
- 本文使用路由组件是vue-router,更多信息请查看官网
- 动态路由即从后端请求路由信息,然后转化生成路由信息。所以这里的关键是不会提前知道什么菜单对应什么组件,因此路由声明的时候不再是写死的组件,而是可替换的动态路径。相关的功能就是路由懒加载,以及异步组件
- 具体过程就是导航守卫的前置守卫中,根据是否登录来判断是否请求用户信息以及路由信息,再将请求的路由信息转化成路由,最后添加到路由表
router.beforeEach((to, from, next) => {
if (store.getters.roles.length === 0) {
store
.dispatch('GetUserInfo')
.then(res => {
const roles = res.data.Data.Roles
store
.dispatch('GenerateRoutes', {
roles
})
.then(() => {
router.addRoutes(store.getters.addRouters)
next({
...to,
replace: true
})
})
})
.catch(err => {
store.dispatch('FedLogOut').then(() => {
Message.error(err || 'Verification failed, please login again')
next({
path: '/'
})
})
})
} else {
next()
}
})
- 以上是导航守卫中的设置,下面介绍请求路由信息并转化成路由,详细代码不展示,只贴出转化部分,使用递归方法转化成多级菜单
function formatRoutes(routes) {
const fmRoutes = []
routes.forEach(router => {
const component = router.component
router.component = resolve => {
require(['@/' + component + '.vue'], resolve)
}
} else if (router.template) {
router.component = resolve => {
resolve({
template: router.template
})
}
let children = router.children
if (children && children instanceof Array) {
children = formatRoutes(children)
}
router.children = children
fmRoutes.push(router)
})
return fmRoutes
}
动态加载组件
- 路由的组件直接赋值 template 就不讲了,直接写代码就成,提前注册好组件即可
- 以下写法相信很多地方都可以查到,但是要点很多地方都没注明
- 路由的组件赋值一个方法,内部 require 加载组件。这个官方文档异步组件有写。但注意以下要点:
- 路径的开头要正确,能访问,可以是别名也可以是相对地址
- 后面部分则是限制模块的类型,即文件名
- 所以以下写法,就是编译
@
别名对应地址下所有vue
文件,中间的变量补齐地址即可
- 分析一下,千万不要全部都写变量,比如
require([component], resolve)
,这样 webpack 不知道你的组件会是什么也不知道位置,所以不会编译也不会匹配该组件。注意到没,一个是编译一个是匹配。像上面的写法,组件不会被编译,更别提匹配了。即使假设某组件被编译进去了,在这里单单用变量也是匹配不到的,因为路径的问题。即根据 component 的路径,匹配不到已编译的组件,因为匹配期间不会再计算代码所在文件路径相对 component 的路径。比如 component 的值分别为@/views/index.vue
、../views/index.vue
、./views/index.vue
,运行期间这些直接拿去跟已注册组件匹配,并不会再次计算真实路径
- 看不懂上面也没关系,没经历过确实不太容易理解。经过上面的解释再理解下面写法就 ok 了,把下面的写法看成常规的
require(['@/views/index.vue'], resolve)
没毛病吧,再换成下面写法,webpack 知道组件位于@/views/
,组件后缀名.vue
,该文件夹的 vue 文件统统编译,变的只有中间部分路径
router.component = resolve => {
require(['@/views/' + component + '.vue'], resolve)
}
动态生成页面
- 有了以上基础再来看这里。这里的动态生成页面是指一个路由对应的组件如果存在则加载,不存在则用 template 赋值一个默认页面
- 此功能可用于大量结构类似的页面,比如很多菜单对应的都是表格页,常见于中后台管理系统。因为会先尝试加载默认路径,不存在才使用默认页,所以个别页面只需要在默认路径放置组件即可覆盖默认页面
if (router.component) {
const component = router.component
router.component = resolve => {
require(['@/' + component + '.vue'], resolve)
}
} else if (router.template) {
router.component = resolve => {
resolve({
template: router.template
})
}
} else {
const component = `${router.name}/index`
router.component = async resolve => {
try {
await require(['@/views/' + component + '.vue'], resolve)
} catch {
console.log('@/views/' + component + '.vue不存在,加载默认模板')
resolve({
template: `<table-base table-name="${router.name}" />`
})
}
}
}
最后
打开App,阅读手记
热门评论
求发一下mock数据吗?感谢,1361637016@qq.com
帮大忙了,谢谢😀