動態路由
- 路由組件是vue-router
- 動態路由即從后端請求路由信息,然后轉化生成路由信息。所以這里的關鍵是不會提前知道什么菜單對應什么組件,因此路由聲明的時候不再是寫死的組件,而是可替換的動態路徑。相關的功能就是路由懶加載,以及異步組件
- 具體過程就是導航守衛的前置守衛中,根據是否登錄來判斷是否請求用戶信息以及路由信息,再將請求的路由信息轉化成路由,最后添加到路由表
router.beforeEach((to, from, next) => {
if (store.getters.roles.length === 0) {
// 判斷當前用戶是否已拉取完user_info信息,得到用戶信息后立即請求路由信息
store
.dispatch('GetUserInfo')
.then(res => {
// 拉取user_info
const roles = res.data.Data.Roles // note: roles must be a array! such as: ['editor','develop']
store
.dispatch('GenerateRoutes', {
roles
})
.then(() => {
// 執行GenerateRoutes動作后,store.getters.addRouters得到的就是內置的路由以及請求的路由的集合
router.addRoutes(store.getters.addRouters) // 動態添加可訪問路由表
next({
...to,
replace: true
}) // hack方法 確保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
})
.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
}
動態加載組件
- 分析一下,千萬不要全部都寫變量,比如
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 {
// 如果沒有指定component路徑並且沒有設置template,嘗試加載默認路徑位置組件或用默認頁面
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}" />`
})
}
}
}