zoukankan      html  css  js  c++  java
  • vue 动态菜单以及动态路由加载、刷新采的坑

    需求:


    从接口动态获取子菜单数据 动态加载 要求只有展开才加载子菜单数据 支持刷新,页面显示正常

    思路:

    一开始比较乱,思路很多。想了很多

    首先路由和菜单共用一个全局route, 数据的传递也是通过store的route, 然后要考虑的俩个点就是一个就是渲染菜单和加载路由,可以在导航首位里处理路由,处理刷新。
    还有一个地方就是菜单组件里展开事件里面 重新生成菜单数据,路由。大体思路差不多,做完就忘了..... 刷新的问题需要用本地缓存处理,之前一直缓存这个route 大数据,但是
    这个localstore 缓存的只是字符串,不能缓存对象,这样的话,菜单是出来了,动态的路由404,因为json.parse 转出来的对象 不是真实路由数据,还需要单独处理component 这个是个函数对象,
    都是坑....所以之前走了点弯路,思路没想好。


    第二天,重新整理思路,想了下,为啥要缓存整个route对象,傻是不是,动态的数据只是一部分,三级菜单...何不分开存储,本地存储动态菜单数据,利用完整的路由模板,取出来的初始化路由对象,
    然后,循环菜单数据,动态设置children属性,生成一个新的完整的路由对象,addRoute不是更好吗
    想到这里,整理下完整思路


    【定义全局route对象】=> 【导航首位判断刷新、初始化加载 store中route为空】=> 【初始化路由和菜单】=> 【菜单展开事件里面,请求接口,拿到子菜单数据,localStore 存储菜单数据,更新路由】
    还有一些小坑 比如重复路由、刷新404问题、刷新白屏、异步处理...

    教训:

    问题肯定能解决,折腾几天,最后才发现思路最重要 

    思路错误,就是浪费时间

    先想好思路,完整的实现路线 先干什么后干什么 其中遇到技术难点再去百度

    分享正文:

    暴力贴代码!!!!!!!!!!!!!

    全局定义store route对象 都会,忽略
    import Vue from 'vue'
    import Router from 'vue-router'
    import Layout from '@/layout'
    
    Vue.use(Router)
    
    export const constantRoutes = [{
      path: '/login',
      name: 'login',
      component: () => import('@/views/login/index'),
      hidden: true,
    }, {
      path: '/404',
      name: '404',
      component: () => import('@/views/error-page/404'),
      hidden: true
    }, {
      path: '/401',
      name: '401',
      component: () => import('@/views/error-page/401'),
      hidden: true
    }, {
      path: '/',
      component: Layout,
      redirect: '/dashboard',
      children: [
        {
          path: 'dashboard',
          component: () => import('@/views/dashboard/index'),
          name: 'dashboard',
          meta: { title: '首页', icon: 'documentation' }
        },
        {
          path: 'xxx',
          component: () => import('xxxxx'),
          name: 'xxx',
          meta: { title: 'XXX', icon: 'component' },
          children: [
              {
                path: 'host',
                name: 'host',
                meta: { 
                  title: 'xxx', 
                  key: 'host'
                }
              },
              {
                path: 'control',
                name: 'control',
                alwaysShow: true,
                meta: { 
                  title: 'xxx', 
                  key: 'control'
                },
                children: []
              },
              {
                path: 'signal',
                name: 'signal',
                alwaysShow: true,
                meta: { 
                  title: 'xxx', 
                  key: 'signal',
                },
                children: [] 
              },
              {
                path: 'gateway',
                name: 'gateway',
                alwaysShow: true,
                meta: { 
                  title: 'xxx', 
                  key: 'gateway'
                },
                children: []
              } 
          ]
        },
        {
          path: 'meeting',
          name: 'meting',
          meta: { title: 'xxx', icon: 'list' }
        },
        {
          path: 'traces',
          component: () => import('@/views/xxx'),
          name: 'traces',
          meta: { title: 'xxx', icon: 'chart' }
        }
    ]
    }, 
      {
        path: '*',
        redirect: '/404',
        hidden: true
      }
    ]
    
    const router = new Router({
      // mode: 'history', // require service support
      scrollBehavior: () => ({
        y: 0
      }),
      //routes: constantRoutes 守卫初始化,这里注释掉
    })
    
    //路由重复的问题 解决
    router.$addRoutes = (params) => {
      router.matcher = new Router({ // 重置路由规则
        scrollBehavior: () => ({
          y: 0
        })
      }).matcher
      router.addRoutes(params) // 添加路由
    }
    
    export default router
    //监听路由守卫 生成动态路由
    router.beforeEach((to, from, next) => {
      
      const routes = store.state.app.routes
    
      console.error('beforeEach 守卫执行了')
    
      //处理首次加载 刷新
      if(routes.length === 0){
         console.error('首次/刷新了')
    
         //更新路由缓存
         const cacheRoute = getLocalRouteInfo()
         
         const routeValue = asyncRouteDataToRoute(cacheRoute.asyncRouteData, constantRoutes)
         
         store
          .dispatch('app/setRoutes', routeValue)
    
         router.$addRoutes([...routeValue])
    
         next({
            ...to,
            replace: true
         })
         return
       } 
    
       next()
    })
    /**
     * 更新三级子菜单 路由元数据
     */
    export const updateIPChildRoutes = function(routes, path, children) {
        return setRouteArrayChildren(routes, path, children)
    }
    
    /**
     * 根据父菜单加载子菜单
     * @param {*} routeKey 
     * @returns 
     */
    export const generateIPChildRoutes =  function(routeKey) {
        return new Promise((resolve, reject) => {
          if (!routeKey) return
          
          
          // const start = getDateSeconds(new Date())
          // const end = setDateSeconds(new Date(), 15, 'm')
          
          const filterAddr = grafanaAddrs.filter(addr => addr.key === routeKey)[0]
          const matchup = filterAddr.matchup
      
          const params = {
            matchup
          } 
      
          //动态添加routers
          try {
            fetchIPInstance(params).then(ipAddrs => {
              const ipRoutes = []
              ipAddrs.forEach(
                addr => {
                    const ipInstance = addr.instance.replace(/^(.*):.*$/, "$1")
      
                    if(!isIPAddress(ipInstance)) 
                      return
      
                    const existRoute = ipRoutes.find(ip => ip.meta && ip.meta.key === ipInstance)
      
                    !existRoute && ipRoutes.push(
                      {
                        path: ipInstance,
                        name: ipInstance,
                        meta: { 
                            title: ipInstance, 
                            key: ipInstance
                        }
                      }
                    )
                }
              )
              resolve(ipRoutes)
            })
          } catch (error) {
            reject(error)
            console.error(`加载子菜单错误`)
          }
        })
    }
    import { isArray, setRouteArrayChildren } from './tool'
    
    // 设置路由缓存值
    const localRouteKey = "LOCALROUTESET";
    
    /**
     * currentPath: '' //当前访问的路由路径
     * routeData: [], //存储的完整路由数据(仅加载菜单可用)
     * asyncRouteData: [] //动态的路由数据(生成新路由使用)
     * {
     *    parentKey //父级key
     *    route: [
     *      {
                path: ,
                name: ,
                meta: { 
                    title: , 
                    key: 
                }
            }
     *    ]
     * }
     */
    
    export function getLocalRouteInfo() {
      const data = localStorage.getItem(localRouteKey);
    
      return data ? JSON.parse(data) : {};
    }
    
    export function setLocalRouteInfo(data) {
      const localData = getLocalRouteInfo();
    
      localStorage.setItem(
        localRouteKey,
        JSON.stringify({
          ...localData,
          ...data,
        })
      );
    }
    
    export function removeLocalRouteInfo() {
      localStorage.removeItem(localRouteKey);
    }
    
    /**
     * 本地缓存 转化成路由元数据
     * @param {*} constantRoutes 路由模板
     */
    export function asyncRouteDataToRoute(asyncRouteData, constantRoutes) {
       let route = constantRoutes
       if (isArray(asyncRouteData) && asyncRouteData.length > 0) {
         asyncRouteData.forEach(
            data => {
              route = setRouteArrayChildren(route, data.parentKey, data.route)
            }
         )
       }
       return route
    }
    /**
     * 设置路由children属性
     * @param {*} routes 
     * @param {*} path 
     * @param {*} children 
     * @returns 
     */
    export const setRouteArrayChildren = function(routes, path, children) {
    
      if (!isArray(routes) || !path)
         return new Array()
      
      for (const route of routes) {
        if (isArray(route.children)) {
          if (route.path === path && route.children.length === 0) {
            route.children.push(...children)
          } else {
            setRouteArrayChildren(route.children, path, children)
          }
        }
      }
    
      return routes
    }
    onExpandMenu(key, keyPath) {
          console.error(key, keyPath)
    
          const path = key.substring(key.lastIndexOf('/') + 1)
          console.error(path)
          
    
          //动态生成监控三级菜单/路由
          const ipAddrKeys = []
          grafanaAddrs.forEach(
            addr => {
              if (addr.matchup) {
                ipAddrKeys.push(addr.key)
              }
            }
          )
    
          if (path && ipAddrKeys.includes(path)) {
    
             generateIPChildRoutes(path)
             .then(ipAddrs => {
               
              if (isArray(ipAddrs)) {
    
                //缓存动态路由数据
                const localRouteInfo = getLocalRouteInfo()
                const cacheRoutes = localRouteInfo.asyncRouteData || []
                cacheRoutes.push(
                    {
                        parentKey: path,
                        route: ipAddrs
                    }
                  )
                setLocalRouteInfo({
                  asyncRouteData : cacheRoutes
                })
    
                //更新route
                let asyncRoutes = store.state.app.routes
    
                asyncRoutes = updateIPChildRoutes(asyncRoutes, path, ipAddrs)
                
                store
                  .dispatch('app/setRoutes', asyncRoutes)
                
                router.$addRoutes([...asyncRoutes])
    
              }
             })
          }
        }

    其他代码 不是核心的 不贴了 

     

  • 相关阅读:
    【Mysql】了解Mysql中的启动参数和系统变量
    【Mysql】初识MySQL
    【分布式搜索引擎】Elasticsearch之开启Elasticsearch的用户名密码验证
    SpringBoot------整合MyBatis
    SpringBoot------自定义拦截器
    SpringBoot------Servlet3.0的注解自定义原生Listener监听器
    SpringBoot------Servlet3.0的注解自定义原生Servlet
    SpringBoot------拦截器Filter的使用
    SpringBoot------如何将项目打成war包
    SpringBoot------Maven Install报错
  • 原文地址:https://www.cnblogs.com/sybboy/p/15412322.html
Copyright © 2011-2022 走看看