Случай:vue-element-asyncLogin
2020-2-8 Обновление
Оптимизируйте процесс, упростите логику, удалите файл _import.js и измените его на прямой динамический импорт.
Оптимизировать страницы 404
2020-1-17 Обновление
Обновлен до последней версии шаблона vue-element-template.
Добавить идеи
Оптимизировать часть кода
Увеличьте группу обмена QQ, если у вас есть какие-либо вопросы, добавьте группу
предисловие
Опубликовал статью о Наггетс в начале годаВспомните реализацию маршрутизации динамического рендеринга Vue., теперь код проходит постоянный Review
Теперь предыдущий метод реализации полностью оптимизирован, объем кода значительно уменьшен, логика проще, а также более стабильна.
Демонстрация была размещена на github, добро пожаловать в игру~~vue-element-asyncLogin, Ваш старт - моя мотивация!
Аутентификация-интерфейсная маршрутизация VS Аутентификация-динамическая маршрутизация
Считается, что внешняя маршрутная аутентификация понятна до тех пор, покаvue-element-adminЯ знаю, что план внешней аутентификации вполне осуществим, понятен, умерен и может быть использован в проекте, тогда где преимущество динамической маршрутизации?
- Внешняя аутентификация не является гибкой, и онлайн-версию необходимо переупаковывать каждый раз, когда вы изменяете разрешения.
- Малые и средние проекты
前端鉴权Очевидно, его проще использовать, стоимость ниже, и программистам не нужен 996 (туман), но для проектов со многими уровнями разрешений и относительно больших проектов поддержка этого набора маршрутов аутентификации, несомненно, является большим проектом, и это не легко Для частых изменений ошибки будут появляться чаще, и нагрузка на интерфейсных инженеров значительно возрастет.В настоящее время кажется, что внешняя аутентификация больше не является хорошим решением. - Динамическая маршрутизация — это не возврат к эпохе слэш-энд-бёрна, а новый образ мышления. роли передаются на бэк-энд контроль, а фронт-энду не нужно управлять маршрутизацией, в лучшем случае только проблема гранулярного управления разрешениями
Реализовать идеи
- Маршрутный переход Сначала определите, вошли ли вы в систему. Если вы не вошли в систему, вы можете получить доступ только к странице белого списка, а все остальные страницы будут перенаправлены на страницу входа.
- Запускается поведение при входе в систему, получается динамическая маршрутизация, информация о динамической маршрутизации рекурсивно анализируется, и в то же время addRouter сохраняется в Vuex, а статус маршрутизации записывается.
- Страницы перехода не будут получать динамические маршруты, обновите страницу, чтобы снова получить динамические маршруты
По сравнению с использованием localStorage для хранения статуса входа в систему ранее, статус входа теперь управляется файлами cookie.
Вся информация о маршрутизации передается для управления Vuex, а не из localStorage, что повышает стабильность системы.
Настройка базовой маршрутизации
Конкретные идеи реализации
router/router.js
// ......
// 静态路由
export const StaticRouterMap = [
{
path: '/login',
component: login,
meta: { title: '管理员登录' },
hidden: true
},
{
path: '/user',
component: userLogin,
redirect: '/user/userlogin',
name: 'user',
hidden: true,
children: [
{
path: 'userLogin',
component: () => import('@/views/userLogin/components/login'),
meta: { title: '商户登录' }
},
{
path: 'userRegistry',
component: () => import('@/views/userLogin/components/registry'),
meta: { title: '商户注册' }
}
]
},
{
path: '/',
component: Layout,
redirect: '/dashboard',
name: 'dashboard',
children: [
{
path: 'dashboard',
component: () => import('@/views/dashboard/index'),
meta: { title: '根目录', icon: 'dashboard', affix: true }
}
]
},
{
path: '/404',
component: () => import('@/views/404'),
hidden: true
}
]
export default new Router({
mode: 'history',
scrollBehavior: () => ({ y: 0 }),
routes: StaticRouterMap
})
Настройте структуру маршрутизации с помощью внутренних студентов (json ниже)
Серверная часть будет динамически возвращаться к структуре маршрутизации на основе текущих разрешений пользователя, и внешнему интерфейсу больше не нужно учитывать разрешения.
[{
id: 1,
name: 'Example',
code: null,
description: null,
url: '/example',
component: 'layout',
generatemenu: 1,
sort: 0,
parentId: null,
permName: null,
redirect: '/example/table',
title: '普通用户',
icon: 'example',
children: [
{
id: 2,
name: 'Table',
code: null,
description: null,
url: 'table',
component: 'table',
generatemenu: 1,
sort: 0,
parentId: 1,
permName: null,
redirect: '',
title: 'Table',
icon: 'table',
children: null
},
{
id: 3,
name: 'Tree',
code: null,
description: null,
url: 'tree',
component: 'tree',
generatemenu: 1,
sort: 0,
parentId: 1,
permName: null,
redirect: '',
title: 'Tree',
icon: 'tree',
children: null
}
]
}]
Анализировать начальные данные маршрутизации серверной части как доступные данные
Обработка необработанных данных маршрутизации серверной части
../utils/addRouter
Рекурсивная запись более стабильна и требует меньше кода, чем рекурсивное удаление в предыдущих версиях.
Уведомление,Структура маршрутизации соответствует структуре каталогов
/**
* 生成路由
* @param {Array} routerlist 格式化路由
* @returns
*/
export function addRouter(routerlist) {
const router = []
try {
routerlist.forEach(e => {
let e_new = {
path: e.url,
name: e.name,
component: () => e.component === 'layout' ? import('@/layout') : import(`@/views/${e.component}/index`)
}
if (e.children) {
const children = addRouter(e.children)
// 保存权限
e_new = { ...e_new, children: children }
}
if (e.redirect) {
e_new = { ...e_new, redirect: e.redirect }
}
if (e.generatemenu === 0) {
e_new = { ...e_new, hidden: true }
}
if (e.icon !== '' && e.title !== '') {
e_new = { ...e_new, meta: { title: e.title, icon: e.icon } }
} else if (e.title !== '' && e.icon === '') {
e_new = { ...e_new, meta: { title: e.title } }
}
router.push(e_new)
})
} catch (error) {
console.error(error)
return []
}
return router
}
обработанный маршрут
Обработанный нами маршрут нужно срастить с существующим роутером, а правила обработки маршрутов нужно модифицировать в соответствии с требованиями.
(Основное) Объединение маршрутов
Все вышеперечисленное является подготовительной работой初始路由вернулся с бэкендом动态路由соединение
Эта часть кода также является ядром оптимизации.
import router from './router'
import store from './store'
import user from './store/modules/user'
import { getToken, removeToken } from './utils/auth'
import NProgress from 'nprogress' // Progress 进度条
import 'nprogress/nprogress.css' // Progress 进度条样式
import { Message } from 'element-ui'
import { getRouter } from './api/login'
import { addRouter } from './utils/addRouter'
const whiteList = ['/login']
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
// 判断cookice是否存在 不存在即为未登录
if (to.path !== '/login') {
if (user.state.init) {
// 获取了动态路由 data一定true,就无需再次请求 直接放行
next()
} else {
// data为false,一定没有获取动态路由,就跳转到获取动态路由的方法
gotoRouter(to, next)
}
} else {
Message({ message: '您已经登录', type: 'info' })
next('/')
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
// 免登陆白名单 直接进入
next()
} else {
if (to.path !== '/login') {
// 重定向到登录页面 不能这么写 因为假如之前的角色是 管理员页面 后又登陆了非管理员 重定向的页面就可能不存在,就会导致404
// next(`/login?redirect=${to.path}`)
next('/login')
} else {
next()
}
}
}
})
router.afterEach((to, from) => {
NProgress.done() // 结束Progress
})
function gotoRouter(to, next) {
getRouter(store.getters.token) // 获取动态路由的方法
.then(res => {
console.log('解析后端动态路由', res)
const asyncRouter = addRouter(res.data.router) // 进行递归解析
store.dispatch('user/setroles', res.data.permit)
return asyncRouter
})
.then(asyncRouter => {
router.addRoutes(asyncRouter) // vue-router提供的addRouter方法进行路由拼接
console.log(asyncRouter)
store.dispatch('user/setRouterList', asyncRouter) // 存储到vuex
store.dispatch('user/GetInfo')
store.commit('user/set_init', true)
next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
})
.catch(e => {
console.log(e)
removeToken()
})
}
Логика внутри Vuex
import { StaticRouterMap } from '../../router/index'
state: {
//.....
RouterList: [] // 动态路由
},
mutations: {
set_router: (state, RouterList) => {
state.RouterList = RouterList
}
},
action: {
// 动态设置路由 此为设置设置途径
setRouterList({ commit }, routerList) {
commit('set_router', StaticRouterMap.concat(routerList)) // 进行路由拼接并存储
},
}
Гораздо проще, чем предыдущая логика
Измените адрес маршрутизации приложения на боковой панели.
Следует отметить, что маршруты, объединенные через addRoutes, не будутthis.$router.options.routesПолучите его, поэтому вам нужно соединить полученный маршрут сthis.$router.options.routesначальство
Наконец, измените код, который отображает часть раздела боковой панели.
src\views\layout\components\Sidebar\index.vue
computed: {
// ....
routes() {
return this.$store.getters.routerList
},
// ....
}
Я тщательно подготовил простую демонстрациюvue-element-asyncLogin, добро пожаловать в опыт, если это поможет вам, пожалуйста, не скупитесь на старт~~1