フロントエンドは動的ルーティングを実装します(バックエンドは権限ルーティングを返します)。

ここに画像の説明を挿入

実装のアイデア

1. フロントエンドは静的ルート (ログイン ログイン ページ、アクセス許可を必要としないデフォルト ルート) を定義します。
2. ユーザーがログインすると、インターフェイスを調整してユーザー情報を取得し、ホームページにログインします。
3フロントエンドとリアエンドから返されるルートの形式を定義します
4. beforeEach のルート ナビゲーション フックで、動的ルーティングを取得するようにインターフェイスを調整し、フロントエンドで利用可能なルーティング データとしてデータを再帰的に処理し、router.addRouters を使用します。 () ルーティングを追加します

ステップ 1: フロントエンドで静的ルートを定義します (アクセス許可を必要としないログイン ページのデフォルト ルート)

ルーター/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

ステップ 2: ユーザーがログインすると、インターフェースを呼び出してユーザー情報を取得し、ホームページにログインします。

ログイン/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
      })
    }
  }

添付ファイル: vuex 永続化処理:vuex-persistedstateプラグインを使用してユーザー ウェアハウスのコンテンツを 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,
        }
      },
    }),
  ],
})

ステップ 3: フロントエンドとバックエンドでルートによって返される形式を定義する

// 后台返回的数据结构
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

ステップ 4: 各処理の前にナビゲーション フックをルーティングする

ルーティングフックロジック:

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

ルーティング ナビゲーション ガード:

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()
})

注意
ここでは、非同期ルーティングとルーティング ステータスのデータが routerList.js に入れられていますが、
キャッシュがないのはこれが理由です。ユーザーが更新すると、ここのデータはリセットされ、フックが再ウォークされると、インターフェースはルーティング情報を取得するように調整されます。
(なぜルートを sessionStorage に置かないのでしょうか?その理由は、ルート配列内のコンポーネントを sessionStorage に保存できないためです。() => import(@/views/${userAuth.component}) は sessionStorage に保存できません。)

取得したユーザー情報は vuex に保存して永続化する必要がありますが、取得したメニューは vuex に永続化されないため、ユーザーは更新時に情報をクリアし、メニューを取得するインターフェイスを再取得します。これは次のコードです。

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)
}

当社は現在バックエンドリターンルーティングを使用して権限管理を行っています

それがあなたを助けることができることを願っています

リファレンスコードはgithubにありますスターを付けてください

おすすめ

転載: blog.csdn.net/weixin_44582045/article/details/132578620