Vue에서 백그라운드 모니터링의 또 다른 사고방식 - 동적 루트의 실현과 최적화

24278 단어
사내 의 그림 한 장 을 빌려 쓰다
전언
올해 초에 디킨에서 Vue 동적 렌더링 루트의 실현을 기록하는 글을 발표했는데, 현재 코드는 끊임없는 Review를 거치고 있다.
현재 이전의 실현 방법을 완전히 최적화하여 코드량이 많이 감소하고 논리가 더욱 간단하며 동시에 더욱 안정적이다
demo는github에 배치되었습니다. 환영합니다~~vue-element-asyncLogin, 당신의 start는 나의 동력입니다!
감권-전단 루트 VS 감권-동적 루트
전단 루트 감권은 vue-element-admin을 이해한 적이 있다면 전단 루트 감권 방안은 완전히 실행할 수 있고 사고방식이 뚜렷하며 난이도가 적당하며 프로젝트에서 충분히 사용할 수 있다고 믿는다. 그러면 상대적으로 동적 루트의 장점은 어디에 있는가?
  • 전단 감시권이 유연성이 부족하고 온라인 버전은 매번 권한 페이지를 수정할 때마다 프로젝트를 다시 포장해야 한다
  • 중소형 프로젝트 중 은 더욱 사용하기 좋고 원가가 낮으며 프로그래머들도 996(안개)를 쓰지 않는다. 그러나 권한 등급이 많고 비교적 큰 프로젝트에 대해 이 감권 루트를 유지하는 것은 의심할 여지없이 큰 프로젝트이다. 그리고 빈번한 변경에 대한 수요에 직면하면 버그가 더욱 빈번해지고 전방 엔지니어의 작업량이 크게 증가한다.이럴 때는 전단 감권이 더 이상 좋은 방안이 아닌 것 같다
  • 동적 루트는 칼로 불씨를 갈던 시대로 돌아가는 것이 아니라 새로운 사고방식이다. 루트 설정은 전면에서 이루어지고 상태는 후단에 맡긴다. 서로 다른 역할의 루트 표시는 후단에 맡긴다. 전단은 루트를 관리할 필요가 없고 권한의 과립화 문제만 관리해야 한다

  • 생각을 실현하다
  • 루트가 바뀌어 로그인 여부를 판단하고 화이트리스트 페이지만 방문할 수 있으며, 다른 페이지를 방문하면 모두 로그인 페이지로 바꿉니다
  • 로그인 행위가 터치하여 동적 루트를 얻고 동적 루트 정보를 귀속적으로 분석하며addRouter를 Vuex에 저장하고 루트를 얻는 상태를 기록한다
  • 점프 페이지는 동적 루트를 얻지 못하고, 페이지를 새로 고침하면 동적 루트를 다시 얻는다
  • 이전에 localStorage 저장소를 사용한 로그인 상태와 비교하여 현재 로그인 상태를 cookice에 맡겨 관리합니다
    라우팅 정보는 모두 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": "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' //        
    
    /**
     *     
     * @param {Array} routerlist      
     * @returns
     */
    export function addRouter(routerlist) {
      const router = []
      routerlist.forEach(e => {
        let e_new = {
          path: e.url,
          name: e.name,
          component: _import(e.name)
        }
        if (e.children) {
          e_new = Object.assign({}, e_new, { children: addRouter(e.children) })
        }
        if (e.redirect) {
          e_new = Object.assign({}, e_new, { redirect: e.redirect })
        }
        if (e.generatemenu == 0) {
          e_new = Object.assign({}, e_new, { hidden: true })
        }
        if (e.icon !== '' && e.title !== '') {
          e_new = Object.assign({}, e_new, {
            meta: { title: e.title, icon: e.icon }
          })
        } else if (e.title !== '' && e.icon === '') {
          e_new = Object.assign({}, e_new, { meta: { title: e.title }})
        }
        router.push(e_new)
      })
      return router
    }
    

    처리 후 라우팅
    우리가 처리한 루트 뒤에는 기존의router와 연결해야 하며, 여기에는 수요에 따라 루트 처리 규칙을 수정해야 한다
    [{
      "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 { 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']
    var data = false //   demo       ,        vuex 
    router.beforeEach((to, from, next) => {
      NProgress.start()
      if (getToken()) {
        //   cookice             
        if (to.path !== '/login') {
          if (data) {
            //         data  true,            
            next()
          } else {
            // data false,          ,             
            gotoRouter(to, next)
          }
        } else {
          Message({ message: '     ', type: 'info' })
          next('/')
        }
      } else {
        data = false
        if (whiteList.indexOf(to.path) !== -1) {
          //            
          next()
        } else {
          if (to.path !== '/login') {
            //                                                       ,    404
            // next(`/login?redirect=${to.path}`)
            next('/login')
          } else {
            next()
          }
        }
      }
    })
    
    router.afterEach(() => {
      NProgress.done() //   Progress
    })
    
    function gotoRouter(to, next) {
      getRouter(store.getters.token) //          
        .then(res => {
          console.log('        ', res.data.data)
          const asyncRouter = addRouter(res.data.data) //       
          //             ,     ,      404   .       
          asyncRouter.push({ path: '*', redirect: '/404', hidden: true })
          return asyncRouter
        })
        .then(asyncRouter => {
          router.addRoutes(asyncRouter) // vue-router   addRouter        
          data = true //         
          store.dispatch('setRouterList', asyncRouter) //    vuex
          store.dispatch('GetInfo')
          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
        },
       	// ....
      }
    

    저는 간단한 demo vue-element-async Login을 정성껏 준비했습니다. 체험을 환영합니다. 도움이 된다면 스타트를 아끼지 마세요.
    전재 대상:https://juejin.im/post/5caeb3756fb9a068967791b3

    좋은 웹페이지 즐겨찾기