需求:
從介面動態獲取子選單資料 動態載入 要求只有展開才載入子選單資料 支援重新整理,頁面顯示正常
思路:
一開始比較亂,思路很多。想了很多
首先路由和選單共用一個全域性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]) } }) } }
其他程式碼 不是核心的 不貼了