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]) } }) } }
其他代碼 不是核心的 不貼瞭
總結
到此這篇關於vue動態菜單、動態路由加載以及刷新踩坑的文章就介紹到這瞭,更多相關vue動態菜單、動態路由加載內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!