api server已經有一個最基本的架構了,我們回到前端,開始制作一個使用者管理界面吧。
路由管理與Layout
從main.js可以看到渲染的入口是App.vue
import App from './App'
new Vue({
el: '#app',
router,
store,
i18n,
render: h => h(App)
})
App.vue裡的模闆很簡單,就是一個router-view
<template>
<div id="app">
<router-view />
</div>
</template>
結合之前分析過的permission.js,中間有個白名單:
如果是未登入使用者(判斷依據就是store中沒有token),通路的url又不在這個白名單中,就強行跳轉到login頁面
對于已經登入過,但store中還沒有使用者角色資訊的情況,先調用info接口擷取角色資訊,根據添加動态路由配置,最後在将頁面路由到指定的url
const { roles } = await store.dispatch('user/getInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
現在我們知道前端的路由配置都是在store/permission.js中的generateRoutes中實作的,檢視相關代碼,generateRoutes會根據使用者角色生成對應的動态路由規則,最後将這些規則與constantRoutes中定義的靜态規則合并到一起。
const mutations = {
SET_ROUTES: (state, routes) => {
state.addRoutes = routes
state.routes = constantRoutes.concat(routes)
}
}
const actions = {
generateRoutes({ commit }, roles) {
return new Promise(resolve => {
let accessedRoutes
if (roles.includes('admin')) {
accessedRoutes = asyncRoutes || []
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)
})
}
}
constantRoutes和asyncRoutes都是在router/index.js中定義的,router元件也是在這裡初始化的,可以看出,初始化時隻配置了靜态規則:
const createRouter = () => new Router({
// mode: 'history', // require service support
scrollBehavior: () => ({
y: 0
}),
routes: constantRoutes
})
const router = createRouter()
constantRoutes靜态規則是一個大的數組,包含了url和對應view組建的映射關系
export const constantRoutes = [{
path: '/redirect',
component: Layout,
hidden: true,
children: [{
path: '/redirect/:path*',
component: () => import('@/views/redirect/index')
}]
},
{
path: '/login',
component: () => import('@/views/login/index'),
hidden: true
},
asyncRoutes也是類似的數組,隻不過額外增加了一些通路控制資訊
export const asyncRoutes = [
path: '/permission',
component: Layout,
redirect: '/permission/page',
alwaysShow: true, // will always show the root menu
name: 'Permission',
meta: {
title: 'permission',
icon: 'lock',
roles: ['admin', 'editor'] // you can set roles in root nav
},
children: [{
path: 'page',
大概了解一下前端路由生成機制,我們發現幾乎所有路由都指向了Layout元件,繼續檢視Layout源碼layout/index.vue,這個元件是整個頁面布局的入口,左邊的siderbar,頂部的navbar,内容區的app-main,以及右邊的浮動設定按鈕right-panel。
<template>
<div :class="classObj" class="app-wrapper">
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
<sidebar class="sidebar-container" />
<div :class="{hasTagsView:needTagsView}" class="main-container">
<div :class="{'fixed-header':fixedHeader}">
<navbar />
<tags-view v-if="needTagsView" />
</div>
<app-main />
<right-panel v-if="showSettings">
<settings />
</right-panel>
</div>
</div>
</template>
跟進看一下layout/components/AppMain.vue的實作,發現他的html模闆裡又包含了一個router-view,這就能讓我更好地了解嵌套路由的配置了。
<template>
<section class="app-main">
<transition name="fade-transform" mode="out-in">
<keep-alive :include="cachedViews">
<router-view :key="key" />
</keep-alive>
</transition>
</section>

了解Layout的結構,就可以知道,layout/components/siderbar/會根據路由規則實作siderbar中的菜單項,layout/components/Navbar實作了navbar,至于app-main,根據各項路由的component參數可知,一般都放在views/目錄下