El front-end implementa enrutamiento dinámico (el back-end devuelve enrutamiento autorizado)

inserte la descripción de la imagen aquí

Ideas de implementación

1. La interfaz define una ruta estática (página de inicio de sesión, que es una ruta predeterminada que no requiere permiso)
2. Cuando el usuario inicia sesión, ajuste la interfaz para obtener información del usuario y luego inicie sesión en la página de inicio
3 Los extremos frontal y posterior definen el formato del retorno de ruta
4. En el gancho de navegación de ruta En beforeEach, ajuste la interfaz para obtener enrutamiento dinámico, procese recursivamente los datos como datos de enrutamiento disponibles en el extremo frontal y use router.addRouters( ) para agregar enrutamiento

Paso 1: definir una ruta estática en el front-end (la ruta predeterminada de la página de inicio de sesión que no requiere permisos)

enrutador/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

// 解决重复点击路由报错的BUG
// 下面这段代码主要解决这个问题 :Uncaught (in promise) Error: Redirected when going from "/login" to "/index" via a navigation guard.
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
    
    
  return originalPush.call(this, location).catch(err => err)
}

// 定义好静态路由
const routes = [
  {
    
    
    path: '/login',
    name: 'login',
    component: () => import('../views/login'),
    hidden: true,
  },
]

const router = new VueRouter({
    
    
  mode: 'history',
  base: process.env.BASE_URL,
  routes,
})

export default router

Paso 2: cuando el usuario inicia sesión, llame a la interfaz para obtener información del usuario y luego inicie sesión en la página de inicio

iniciar sesión/index.vue

methods: {
    
    
    login () {
    
    
      this.$refs.userForm.validate((valid) => {
    
    
        if (valid) {
    
    
          // 模拟登录接口去请求用户数据
          setTimeout(() => {
    
    
            // 这里的res就是模拟后台返回的用户数据
            const res = dynamicUserData.filter((item) => item.username === this.user.username)[0]
            console.log(res)
            // 存储用户的信息及token到vuex,并做sessionStorage持久化处理
            this.$store.commit('User/saveUserInfo',res)
            Message({
    
     type: 'success', message: "登录成功", showClose: true, duration: 3000 })
            this.$router.push({
    
     path: "/index" })
          }, 1000)
        } else return false
      })
    }
  }

Adjunto: procesamiento de persistencia de vuex: use vuex-persistedstatecomplementos para almacenar el contenido del almacén de usuarios en sessionStorage

import Vue from 'vue'
import Vuex from 'vuex'
import User from './modules/user'
import permission from './modules/permission'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)

export default new Vuex.Store({
    
    
  state: {
    
    },
  mutations: {
    
    },
  actions: {
    
    },
  modules: {
    
    
    User,
    permission,
  },
  plugins: [
    createPersistedState({
    
    
      storage: window.sessionStorage, // 可选sessionStorage localStorage
      reducer(val) {
    
    
        return {
    
    
          User: val.User,
        }
      },
    }),
  ],
})

Paso 3: definir el formato devuelto por la ruta en los extremos frontal y posterior

// 后台返回的数据结构
const dynamicUser = [
  {
    
    
    name: '管理员',
    avatar: 'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/ccb565eca95535ab2caac9f6129b8b7a~300x300.image',
    desc: '管理员 - admin',
    username: 'admin',
    password: '654321',
    token: 'rtVrM4PhiFK8PNopqWuSjsc1n02oKc3f',
    routes: [
      {
    
    
        id: 1,
        name: '/',
        path: '/',
        component: 'Layout',
        redirect: '/index',
        hidden: false,
        children: [{
    
     name: 'index', path: '/index', meta: {
    
     title: 'index' }, component: 'index/index' }],
      },
      {
    
    
        id: 2,
        name: '/form',
        path: '/form',
        component: 'Layout',
        redirect: '/form/index',
        hidden: false,
        children: [{
    
     name: '/form/index', path: '/form/index', meta: {
    
     title: 'form' }, component: 'form/index' }],
      },
      {
    
    
        id: 3,
        name: '/example',
        path: '/example',
        component: 'Layout',
        redirect: '/example/tree',
        meta: {
    
     title: 'example' },
        hidden: false,
        children: [
          {
    
     name: '/tree', path: '/example/tree', meta: {
    
     title: 'tree' }, component: 'tree/index' },
          {
    
     name: '/copy', path: '/example/copy', meta: {
    
     title: 'copy' }, component: 'tree/copy' },
        ],
      },
      {
    
    
        id: 4,
        name: '/table',
        path: '/table',
        component: 'Layout',
        redirect: '/table/index',
        hidden: false,
        children: [{
    
     name: '/table/index', path: '/table/index', meta: {
    
     title: 'table' }, component: 'table/index' }],
      },
      {
    
    
        id: 5,
        name: '/admin',
        path: '/admin',
        component: 'Layout',
        redirect: '/admin/index',
        hidden: false,
        children: [{
    
     name: '/admin/index', path: '/admin/index', meta: {
    
     title: 'admin' }, component: 'admin/index' }],
      },
      {
    
    
        id: 6,
        name: '/people',
        path: '/people',
        component: 'Layout',
        redirect: '/people/index',
        hidden: false,
        children: [{
    
     name: '/people/index', path: '/people/index', meta: {
    
     title: 'people' }, component: 'people/index' }],
      },
    ],
  },
  {
    
    
    name: '普通用户',
    avatar: 'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/6364348965908f03e6a2dd188816e927~300x300.image',
    desc: '普通用户 - people',
    username: 'people',
    password: '123456',
    token: '4es8eyDwznXrCX3b3439EmTFnIkrBYWh',
    routes: [
      {
    
    
        id: 1,
        name: '/',
        path: '/',
        component: 'Layout',
        redirect: '/index',
        hidden: false,
        children: [{
    
     name: 'index', path: '/index', meta: {
    
     title: 'index' }, component: 'index/index' }],
      },
      {
    
    
        id: 2,
        name: '/form',
        path: '/form',
        component: 'Layout',
        redirect: '/form/index',
        hidden: false,
        children: [{
    
     name: '/form/index', path: '/form/index', meta: {
    
     title: 'form' }, component: 'form/index' }],
      },
      {
    
    
        id: 3,
        name: '/example',
        path: '/example',
        component: 'Layout',
        redirect: '/example/tree',
        meta: {
    
     title: 'example' },
        hidden: false,
        children: [
          {
    
     name: '/tree', path: '/example/tree', meta: {
    
     title: 'tree' }, component: 'tree/index' },
          {
    
     name: '/copy', path: '/example/copy', meta: {
    
     title: 'copy' }, component: 'tree/copy' },
        ],
      },
      {
    
    
        id: 4,
        name: '/table',
        path: '/table',
        component: 'Layout',
        redirect: '/table/index',
        hidden: false,
        children: [{
    
     name: '/table/index', path: '/table/index', meta: {
    
     title: 'table' }, component: 'table/index' }],
      },
      {
    
    
        id: 6,
        name: '/people',
        path: '/people',
        component: 'Layout',
        redirect: '/people/index',
        hidden: false,
        children: [{
    
     name: '/people/index', path: '/people/index', meta: {
    
     title: 'people' }, component: 'people/index' }],
      },
    ],
  },
]

export default dynamicUser

Paso 4: Enrutar el gancho de navegación antes de cada procesamiento

Lógica del enlace de enrutamiento:

是否为白名单:
	是:  直接进入
	不是:判断是否有token
		无token:跳转到login登录页
		有token:判断用户路由状态(是否有路由)
			有路由: 直接进入
			无路由: 调接口获取动态路由
					递归处理返回的路由
					将递归处理好的路由存储到vuex,设置用户路由状态为true
					使用router.addRouters()添加路由

Guardia de navegación de ruta:

import router from './index'
import Layout from '../layout/index'
import NProgress from 'nprogress' // progress bar
import store from '@/store'
import menu from '@/mock/menu.js'

// 路由拼接
function loadView(view) {
    
    
  return () => import(`@/views/${
      
      view}`)
}
// 路由过滤   遍历路由 转换为组件对象和路径
function filterASyncRoutes(data) {
    
    
  // console.log(data)
  const routes = data.filter(item => {
    
    
    if (item['component'] === 'Layout') {
    
    
      item.component = Layout
    } else {
    
    
      item['component'] = loadView(item['component'])
    }
    // 路由递归,转换组件对象和路径
    if (item['children'] && item['children'].length > 0) {
    
    
      item['children'] = filterASyncRoutes(item.children)
    }
    return true
  })
  // 排序
  routes.sort((a, b) => a['id'] - b['id'])
  return routes
}

NProgress.configure({
    
     showSpinner: false }) // NProgress Configuration

// 白名单页面直接进入
const whiteList = ['/login']

router.beforeEach((to, from, next) => {
    
    
  NProgress.start()
  // 白名单页面,不管是否有token,是否登录都直接进入
  if (whiteList.indexOf(to.path) !== -1) {
    
    
    next()
    return false
  }
  // 有token(代表了有用户信息,但是不确定有没有路由信息)
  if (store.state.User.token) {
    
    
    // 判断当前用户是否是登录状态, 是登录状态则一定有路由,直接放行,不是登录状态则去获取路由菜单登录
    // 刷新时store.state.routerList.hasRoutes会重置为false,重新去获取 异步路由
    if (!store.state.routerList.hasRoutes) {
    
    
      setTimeout(() => {
    
    
        const res = menu.filter(item => item.token === store.state.User.token)[0].routes
        const asyncRouter = filterASyncRoutes(res) // 递归处理后台返回的路由
        store.commit('routerList/setRouterList', asyncRouter) // 存储到异步的路由到vuex
        store.commit('routerList/setHasRoutes', true) // 设置登录状态为true
        router.addRoutes(asyncRouter) // 动态添加可访问路由表
        next({
    
     ...to, replace: true }) // hack方法 router.addRoutes之后的next()可能会失效,可能next()的时候路由并没有完全add完成 通过next(to)解决
      }, 500)
    } else {
    
    
      next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面
    }
  }else {
    
    
    next({
    
    path:'/login'})
  }
})

router.afterEach(() => {
    
    
  // finish progress bar
  NProgress.done()
})

注意
Aquí, los datos del enrutamiento asincrónico y el estado del enrutamiento se colocan en routerList.js, pero esta es la razón por la que no hay almacenamiento en caché
: cuando el usuario actualiza, los datos aquí se restablecen y cuando el usuario vuelve a recorrer el camino, el La interfaz se ajustará para obtener información de ruta.
(¿Por qué no poner la ruta en sessionStorage? La razón es que los componentes de la matriz de rutas no se pueden guardar en sessionStorage, () => import(@/views/${userAuth.component}) no se pueden guardar en sessionStorage)

La información del usuario obtenida debe almacenarse en vuex y persistir, pero el menú obtenido se almacena en vuex sin persistencia, de modo que el usuario lo borre al actualizar y vaya a la interfaz para obtener el menú nuevamente, que es la siguiente código

if (!store.state.routerList.hasRoutes) {
    
    
 setTimeout(() => {
    
    
    const res = menu.filter(item => item.token === store.state.User.token)[0].routes
    const asyncRouter = filterASyncRoutes(res) // 递归处理后台返回的路由
    store.commit('routerList/setRouterList', asyncRouter) // 存储到异步的路由到vuex
    store.commit('routerList/setHasRoutes', true) // 设置登录状态为true
    router.addRoutes(asyncRouter) // 动态添加可访问路由表
    next({
    
     ...to, replace: true }) // hack方法 router.addRoutes之后的next()可能会失效,可能next()的时候路由并没有完全add完成 通过next(to)解决
  }, 500)
}

Actualmente, nuestra empresa utiliza el enrutamiento de retorno de back-end para realizar la gestión de autoridad.

Espero que te ayude

El código de referencia está en github Dame una estrella

Supongo que te gusta

Origin blog.csdn.net/weixin_44582045/article/details/132578620
Recomendado
Clasificación