Предыстория: компания намеревается сделать (cms) первую ссылку на внешний интерфейс.vue-element-adminИдея проверяет возможность фронтальной аутентификации. Код, написанный боссом, ясен и достоин изучения. Позже, после рассмотрения многих факторов, сложности фронтальной аутентификации безопасности интерфейса и сложности проект, мы, наконец, решили использовать динамическую форму маршрутизации внутреннего рендеринга
Эта статья относительно устарела, см.Еще одна идея фоновой аутентификации во Vue — реализация и оптимизация динамической маршрутизации
Используется шаблон управления фоном Vue+Element.github
Идеи см. в статье
Реализовать идеи
Некоторые основные идеи и реализация динамической маршрутизации VueРеализация динамической маршрутизации Vue (прохождение маршрутизации в фоновом режиме, получение и создание боковой панели во внешнем интерфейсе)То же самое, основная часть добавила свое собственное понимание
- Каждый раз, когда маршрут переключается, сначала определите, следует ли выполнять вход в систему. После входа в систему будет выполняться логика, связанная с маршрутизацией.
- получить переменную
getRouter, если он существует, он будет освобожден напрямую, потому что существует конфигурация маршрутизации. - Если вы обновите страницу
getRouterПеременная больше не существует, поэтому вам нужно получить ее один раз - получают и хранят в
getRouterвключено, легко использовать позже, уменьшить количество запросов
Ниже приведены конкретные идеи реализации
Настройка базовой маршрутизации
Базовый маршрут — это маршрут, к которому можно получить доступ без входа в систему.
const StaricRouterMap = [
{
path: '/login',
component: login,
hidden: true
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
name: 'dashboard',
hidden: true,
meta: { title: '根目录' },
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index')
}
]
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
},
{
path: '*',
redirect: '/404',
hidden: true
}, // ....
]
export default new Router({
mode: 'history', // 后端支持可开
scrollBehavior: () => ({ y: 0 }),
routes: StaricRouterMap
})
Настройте структуру маршрутизации с помощью внутренних студентов (json ниже)
Серверная часть будет динамически возвращаться к структуре маршрутизации на основе текущих разрешений пользователя, и внешнему интерфейсу больше не нужно учитывать разрешения.
[{
"id": 1,
"name": "Nested",
"code": null,
"description": null,
"url": "/nested",
"generatemenu": 0,
"sort": 0,
"parentId": null,
"permName": null,
"redirect": "/nested/menu1",
"title": "Nested",
"icon": "nested",
"children": [{
"id": 2,
"name": "Menu1",
"code": null,
"description": null,
"url": "menu1",
"generatemenu": 0,
"sort": 0,
"parentId": 1,
"permName": null,
"redirect": "",
"title": "Menu1",
"icon": "menu1",
"children": [{
"id": 4,
"name": "Menu1-1",
"code": null,
"description": null,
"url": "menu1-1",
"generatemenu": 0,
"sort": 0,
"parentId": 2,
"permName": null,
"redirect": "",
"title": "Menu1-1",
"icon": "",
"children": null
}, {
"id": 5,
"name": "Menu1-2",
"code": null,
"description": null,
"url": "menu1-2",
"generatemenu": 0,
"sort": 0,
"parentId": 2,
"permName": null,
"redirect": "",
"title": "Menu1-2",
"icon": "",
"children": null
}]
}, {
"id": 3,
"name": "Menu2",
"code": null,
"description": null,
"url": "menu2",
"generatemenu": 0,
"sort": 0,
"parentId": 1,
"permName": null,
"redirect": "",
"title": "Menu2",
"icon": "menu2",
"children": null
}]
}]
Анализировать начальные данные маршрутизации серверной части как доступные данные
Конечно, это не используется напрямую для маршрутизации рендеринга, нам нужно выполнить рекурсивную обработку, чтобы получить нужные данные.
../router/_import
export default file => {
return map[file] || null
}
const map = {
Nested: () => import('@/views/layout/Layout'),
Menu1: () => import('@/views/nested/menu1/index'),
'Menu1-1': () => import('@/views/nested/menu1/menu1-1'),
'Menu1-2': () => import('@/views/nested/menu1/menu1-2')
}
Обработка необработанных данных маршрутизации серверной части
../utils/addRouter
import _import from '../router/_import'// 获取组件的方法
function addRouter(routerlist) {
routerlist.forEach(e => {
// 删除无用属性
delete e.code
delete e.sort
delete e.generatemenu
delete e.description
delete e.permName
delete e.id
delete e.parentId
e.path = e.url
delete e.url
e.component = _import(e.name) // 动态匹配组件
if (e.redirect === '') {
delete e.redirect
}
if (e.icon !== '' && e.title !== '') { // 配置 菜单标题 与 图标
e.meta = {
title: e.title,
icon: e.icon
}
}
if (e.title !== '' && e.icon === '') {
e.meta = {
title: e.title
}
}
delete e.icon
delete e.title
if (e.children != null) {
// 存在子路由就递归
addRouter(e.children)
}
})
return routerlist
}
export { addRouter }
обработанный маршрут
Обработанный нами маршрут нужно срастить с существующим роутером, а правила обработки маршрутов нужно модифицировать в соответствии с требованиями.
[{
"name": "Nested",
"redirect": "/nested/menu1",
"children": [{
"name": "Menu1",
"children": [{
"name": "Menu1-1",
"children": null,
"path": "menu1-1",
"meta": {
"title": "Menu1-1"
}
}, {
"name": "Menu1-2",
"children": null,
"path": "menu1-2",
"meta": {
"title": "Menu1-2"
}
}],
"path": "menu1",
"meta": {
"title": "Menu1",
"icon": "menu1"
}
}, {
"name": "Menu2",
"children": null,
"path": "menu2",
"component": null,
"meta": {
"title": "Menu2",
"icon": "menu2"
}
}],
"path": "/nested",
"meta": {
"title": "Nested",
"icon": "nested"
}
}]
(Основное) Объединение маршрутов
Все вышеперечисленное является подготовительной работой初始路由вернулся с бэкендом动态路由соединение
Это тоже самое сложное произведение, ссылающееся на какие-то чужие идеи, а позже доработанная версия, это вершина实现思路код
import router from './router'
import store from './store'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css' // Progress 进度条样式
import { Message } from 'element-ui'
import { addRouter } from './utils/addRouter'
var getRouter
router.beforeEach((to, from, next) => {
NProgress.start() // 进度条
if (localStorage.getItem('login_static') === '1') {
if (to.path === '/login') {
Message('您已登录,如需切换用户请退出重新登录')
next({ path: '/' })
}
if (!getRouter) {
if (getRouterList('router')) {
// 路由信息存在 说明请求阶段以及完成 直接解析路由信息
getRouter = getRouterList('router') // 拿到路由
gotoRouter(to, next)
} else {
// localStorage不存在路由信息 这需要 请求路由信息 并解析路由
setRouterList(to, next) // 存储路由到localStorage
}
} else {
// getRouter变量存在 说明路由信息存在 直接通过
next()
}
} else {
if (to.path === '/login') {
next()
} else {
next(`/login`)
}
}
})
router.afterEach(() => {
NProgress.done() // 结束Progress
})
function gotoRouter(to, next) {
try {
getRouter = addRouter(getRouter)
router.addRoutes(getRouter) // 动态添加路由
global.antRouter = router.options.routes.concat(getRouter) // 将路由数据传递给全局变量,做侧边栏菜单渲染工作
next({ to, replace: true })
} catch (error) {
localStorage.setItem('login_static', 0)
}
}
function setRouterList(to, next) {
store.dispatch('getRouter').then(asyncRouter => { // 请求路由数据
localStorage.setItem('router', JSON.stringify(asyncRouter))
getRouter = getRouterList('router') // 拿到路由
gotoRouter(to, next)
})
}
function getRouterList(name) {
return JSON.parse(localStorage.getItem(name))
}
Измените адрес маршрутизации приложения на боковой панели.
Следует отметить, что маршруты, объединенные через addRoutes, не будутthis.$router.options.routesПолучите его, поэтому вам нужно соединить полученный маршрут сthis.$router.options.routesначальство
Наконец, измените код, который отображает часть раздела боковой панели.
src\views\layout\components\Sidebar\index.vue
computed: {
// ....
routes() {
return global.antRouter // 这里应该最好使用vuex的全局变量
},
// ....
}