Vue dynamic menu, dynamic route loading and refresh pitfalls

Vue dynamic menu, dynamic route loading and refresh pitfalls

need:

Dynamically obtain submenu data from the interface. Dynamic loading requires that submenu data is loaded only when it is expanded. Refresh is supported and the page displays normally.

Ideas:

It was a bit chaotic at the beginning, with a lot of ideas. I thought a lot

First of all, the route and menu share a global route, and data is also transmitted through the store route. Then the two points to consider are rendering the menu and loading the route. The route and refresh can be processed in the first place of the navigation.

Another place is to regenerate menu data and routing in the expansion event of the menu component. The general idea is similar, and I forget it after I finish it... The refresh problem needs to be handled by local cache. Previously, the route big data has been cached, but this localstore only caches strings and cannot cache objects. In this case, the menu comes out, but the dynamic route is 404, because the object converted by json.parse is not the real route data, and it needs to be handled separately. Component is a function object.
They are all pitfalls...so I took some detours before and didn’t think my ideas through.

The next day, I reorganized my thoughts and thought about why I had to cache the entire route object. Is that stupid? Dynamic data is only a part of the three-level menu... Why not store it separately? Store the dynamic menu data locally, use the complete route template, take out the initialized route object, and then loop the menu data, dynamically set the children attribute, and generate a new complete route object. Isn't addRoute better? Thinking of this, I sorted out the complete idea.

[Define global route object] => [Refresh the first position of navigation, initialize and load the route in the store to be empty] => [Initialize routing and menu] => [In the menu expansion event, request the interface, get the submenu data, store the menu data in localStore, and update the route]
There are also some small pitfalls such as repeated routing, refreshing 404 problems, refreshing white screen, asynchronous processing...

lesson:

The problem can definitely be solved. After a few days of struggling, I finally realized that the idea is the most important

Wrong thinking is a waste of time

Think of the idea first, the complete implementation route, what to do first and what to do later. If you encounter technical difficulties, go to Baidu

Share the text:

Violent post code! ! ! ! ! ! ! ! ! ! ! ! !

Globally defined store route objects will be ignored

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: 'Homepage', 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 guards initialization, commented out here})

//Solve the problem of repeated routes router.$addRoutes = (params) => {
  router.matcher = new Router({ // Reset routing rules scrollBehavior: () => ({
      y: 0
    })
  }).matcher
  router.addRoutes(params) // Add routes}

export default router
//Monitoring routes to guard dynamic routes router.beforeEach((to, from, next) => {
  
  const routes = store.state.app.routes

  console.error('beforeEach guard executed')

  //Handle the first load refresh if (routes.length === 0) {
     console.error('First time/refreshed')

     //Update route cache const cacheRoute = getLocalRouteInfo()
     
     const routeValue = asyncRouteDataToRoute(cacheRoute.asyncRouteData, constantRoutes)
     
     store
      .dispatch('app/setRoutes', routeValue)

     router.$addRoutes([...routeValue])

     next({
        ...to,
        replace: true
     })
     return
   } 

   next()
})
/**
 * Update the third-level submenu routing metadata */
export const updateIPChildRoutes = function(routes, path, children) {
    return setRouteArrayChildren(routes, path, children)
}

/**
 * Load submenu according to parent menu * @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
      } 
  
      //Dynamically add 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(`Error loading submenu`)
      }
    })
}
import { isArray, setRouteArrayChildren } from './tool'

// Set the route cache value const localRouteKey = "LOCALROUTESET";

/**
 * currentPath: '' //Currently accessed route path* routeData: [], //Stored complete route data (only available for loading menu)
 * asyncRouteData: [] //Dynamic route data (used to generate new routes)
 * {
 * parentKey //parent 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);
}

/**
 * Local cache converted into routing metadata* @param {*} constantRoutes routing template*/
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
}
/**
 * Set the route children attributes * @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)
      

      //Dynamically generate monitoring level 3 menu/routing const ipAddrKeys = []
      grafanaAddrs.forEach(
        addr => {
          if (addr.matchup) {
            ipAddrKeys.push(addr.key)
          }
        }
      )

      if (path && ipAddrKeys.includes(path)) {

         generateIPChildRoutes(path)
         .then(ipAddrs => {
           
          if (isArray(ipAddrs)) {

            //Cache dynamic routing data const localRouteInfo = getLocalRouteInfo()
            const cacheRoutes = localRouteInfo.asyncRouteData || []
            cacheRoutes.push(
                {
                    parentKey: path,
                    route:ipAddrs
                }
              )
            setLocalRouteInfo({
              asyncRouteData : cacheRoutes
            })

            //Update route
            let asyncRoutes = store.state.app.routes

            asyncRoutes = updateIPChildRoutes(asyncRoutes, path, ipAddrs)
            
            store
              .dispatch('app/setRoutes', asyncRoutes)
            
            router.$addRoutes([...asyncRoutes])

          }
         })
      }
    }

Other codes are not core and will not be posted.

Summarize

This is the end of this article about vue dynamic menu, dynamic route loading and refresh pitfalls. For more related vue dynamic menu and dynamic route loading content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Solution to the blank problem of dynamic menu refresh based on Vue
  • Example of using addRoutes to implement dynamic routing in Vue
  • Ideas and methods for implementing multi-level nested breadcrumbs with Vue dynamic routing
  • Detailed explanation of dynamic routing in the vue series [original]
  • Detailed explanation of Vue routing (dynamic routing, routing nesting)
  • Vue dynamic routing configuration and routing parameter passing method
  • Explain what is dynamic routing in vue-router
  • Comprehensive analysis of the basic use of vue router (dynamic routing, nested routing)

<<:  HTML table markup tutorial (6): dark border color attribute BORDERCOLORDARK

>>:  Solutions to common problems using Elasticsearch

Recommend

Implementation of nested jump of vue routing view router-view

Table of contents 1. Modify the app.vue page 2. C...

How to use nginx as a load balancer for mysql

Note: The nginx version must be 1.9 or above. Whe...

How to add vim implementation code examples in power shell

1. Go to Vim's official website to download t...

How to connect to a remote docker server with a certificate

Table of contents 1. Use scripts to encrypt TLS f...

Vue application example code based on axios request encapsulation

Table of contents What is axios? Axios request ty...

How many ports can a Linux server open at most?

Table of contents Port-related concepts: Relation...

Share 10 of the latest web front-end frameworks (translation)

In the world of web development, frameworks are ve...

10 key differences between HTML5 and HTML4

HTML5 is the next version of the HTML standard. M...

Detailed example of mysql trigger usage

MySQL trigger syntax details: A trigger is a spec...

Mysql GTID Mha configuration method

Gtid + Mha + Binlog server configuration: 1: Test...

What are the differences between xHTML and HTML tags?

All tags must be lowercase In XHTML, all tags must...

Implementation of Vue3 style CSS variable injection

Table of contents summary Basic Example motivatio...