<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近在寫vue專案,需要由後臺傳來當前使用者對應許可權的路由表,前端通過調介面拿到後處理(後端處理路由),就是設定vue動態路由啦。
由於錯信了一些網上的文章:(,導致在這個問題上耗費了不少時間,想想,還是自己寫一篇文章來記錄一下那些遇到的坑吧。
接下來手把手記錄一下,如何從零開始設定vue動態路由。
首先呢,先看看靜態路由的設定,簡單預覽一下,熟悉的可以直接跳過,說這部分,是為了熟悉一下路由的設定,設定動態路由其實就是把靜態路由存到資料庫,在取出來放進路由表(靜態是直接寫在路由表裡)。
1.建立router/index.js檔案,這裡只有一些簡單的頁面
import Vue from 'vue' import Router from 'vue-router' import Login from '@/view/login/Login' import Index from '@/layout/Index' import Welcome from '@/layout/welcome/Welcome' Vue.use(Router) export default new Router({ routes: [ { path: '/login', name: 'Login', component: Login }, { path: '/', component: Index, redirect: '/welcome', meta: {requireAuth: true}, children: [ { path: '/welcome', component: Welcome, name: '首頁', meta: {title: '首頁', requireAuth: true} } ] } ] })
2.建立router/permission.js檔案,設定導航守衛,可以在每次路由跳轉前做一些操作,待會獲取動態路由操作也在這裡設定
import router from '@/router/index' import 'element-ui/lib/theme-chalk/index.css' import '@fortawesome/fontawesome-free/css/all.min.css' import NProgress from 'nprogress' import 'nprogress/nprogress.css' NProgress.configure({ easing: 'ease', // 動畫方式 speed: 500, // 遞增進度條的速度 showSpinner: false, // 是否顯示載入ico trickleSpeed: 200, // 自動遞增間隔 minimum: 0.3 // 初始化時的最小百分比 }) // 白名單 const whiteList = ['/login'] // no redirect whitelist // 導航守衛 router.beforeEach((to, from, next) => { NProgress.start() if (to.meta.requireAuth) { // 判斷該路由是否需要登入許可權 if (sessionStorage.getItem('loginName') !== null) { // 判斷本地是否存在token next() // 這裡是待會獲取非同步路由的地方 } else { // 未登入,跳轉到登陸頁面 next({ path: '/login' }) } } else { if (whiteList.indexOf(to.path) !== -1) { next() } else { if (sessionStorage.getItem('loginName') !== null) { // 判斷本地是否存在token next(`/?redirect=${to.path}`) } else { next(`/login?redirect=${to.path}`) } } } }) router.afterEach(() => { // 在即將進入新的頁面元件前,關閉掉進度條 NProgress.done() })
這裡參照了一個外掛,Nprogress,就是下圖的藍色小進度條。不用也可以
3.在main.js裡引入剛才建立的router下的index.js檔案和permission.js檔案,如下
import router from '@/router' import './router/permission' new Vue({ el: '#app', router, store, components: { App }, template: '<App/>' })
4.在App入口中放入路由跳轉的檢視區,跳轉的路由頁面都顯示在這裡
// APP.vue檔案 <div id="app"> <router-view /> </div>
現在靜態路由就配好了,可以正常的跳轉了!
資料夾長這樣
接下來開始設定動態路由了!
有坑的地方我會說明一下。
1.首先呢,router/index.js,沒有什麼需要改的,把你需要動態獲取的路由資訊刪除掉即可,可以留一部分靜態路由,如登入頁,首頁等等,若全刪,routes賦為[]即可。
2.建立一個檔案,我命名為getAsyncRouter.js,用來處理獲取到的動態路由資訊。
// 用於處理動態選單資料,將其轉為 route 形式 export function fnAddDynamicMenuRoutes (menuList = [], routes = []) { // 用於儲存普通路由資料 let temp = [] // 用於儲存存在子路由的路由資料 let route = [] // 遍歷資料 for (let i = 0; i < menuList.length; i++) { // 存在子路由,則遞迴遍歷,並返回資料作為 children 儲存 if (menuList[i].children && menuList[i].children.length > 0) { // 獲取路由的基本格式 route = getRoute(menuList[i]) // 遞迴處理子路由資料,並返回,將其作為路由的 children 儲存 route.children = fnAddDynamicMenuRoutes(menuList[i].children) // 儲存存在子路由的路由 routes.push(route) } else { // 儲存普通路由 temp.push(getRoute(menuList[i])) } } // 返回路由結果 return routes.concat(temp) } // 返回路由的基本格式 function getRoute (item) { // 路由基本格式 let route = { // 路由的路徑 path: item.url, // 路由名 name: item.name, // 路由所在元件 // component: (resolve) => require([`@/layout/Index`], resolve), component: (resolve) => require([`@/view${item.curl}`], resolve), meta: { id: item.id, icon: item.icon }, // 路由的子路由 children: [] } // 返回 route return route }
這裡是兩個函數,把獲取到的資料處理成路由表資料,將其變化成 route 的形式。
fnAddDynamicMenuRoutes
用於遞迴選單資料。getRoute
用於返回某個資料轉換的 路由格式。註釋寫的應該算是很詳細了,主要講一下思路:
route 格式一般如下:
path
:指路由路徑(可以根據路徑定位路由)。name
:指路由名(可以根據路由名定位路由)。component
:指路由所在的元件。children
:指的是路由元件中巢狀的子路由。meta
:用於定義路由的一些元資訊。這裡有個大坑!!! 在設定component的時候,需要動態匯入元件,也就是vue非同步元件,檢視檔案如下
可知,有兩種匯入方式,import和require方式。這裡簡單說一下,
1 import屬於es6匯入方式,只支援靜態匯入,也就是說,你不能夠使用變數或表示式,只能使用字串。
2 require屬於commonJS方式,可以支援動態的匯入,但筆者嘗試中,可以使用``模板字串方式,貌似也無法直接使用變數。這裡儘量用字串拼接,而不是用變數去代替拼接的字串!
由於import不支援動態匯入方式,筆者採用的是require的方式,並且在webpack檔案中有這樣一段話。
綜上所述,就是說,元件的匯入可以使用字串拼接的方式匯入,可以使用模板字串匯入(字串中含有變數),但是使用模板字串匯入時不能夠只使用變數!!必須指定一個目錄,不能全用變數代替!
// 字串拼接方式 component: import('@/view'+'/sys/user') // 模板字串方式,webpack4+版本需使用require方式,注意,`@${item.curl}`,是不行的!必須指定一個目錄,不能全用變數代替 component: (resolve) => require([`@/view${item.curl}`], resolve),
這個現象其實是與webpack import()的實現高度相關的。由於webpack需要將所有import()的模組都進行單獨打包,所以在工程打包階段,webpack會進行依賴收集。
此時,webpack會找到所有import()的呼叫,將傳入的引數處理成一個正則,如:
import('./app'+path+'/util') => /^./app.*/util$/
也就是說,import引數中的所有變數,都會被替換為【.*】,而webpack就根據這個正則,查詢所有符合條件的包,將其作為package進行打包。
所以動態匯入的正確姿勢,應該是儘可能靜態化表達包所處的路徑,最小化變數控制的區域。
3.有了處理動態路由資料的函數,那就需要在合適的地方呼叫,以發揮作用。這時就需要用到beforeEach了,在router/permission.js檔案,設定導航守衛,可以在每次路由跳轉前做一些操作,這裡就是獲取動態路由了
import router from '@/router/index' import 'element-ui/lib/theme-chalk/index.css' import '@fortawesome/fontawesome-free/css/all.min.css' import NProgress from 'nprogress' import 'nprogress/nprogress.css' import {fnAddDynamicMenuRoutes} from '@/router/getAsyncRouter' import {getRouter} from '@/api/sys/Menu' import store from '@/store' NProgress.configure({ easing: 'ease', // 動畫方式 speed: 500, // 遞增進度條的速度 showSpinner: false, // 是否顯示載入ico trickleSpeed: 200, // 自動遞增間隔 minimum: 0.3 // 初始化時的最小百分比 }) // 白名單 const whiteList = ['/login'] // no redirect whitelist // 導航守衛 router.beforeEach((to, from, next) => { NProgress.start() try { // 判斷是否已經獲取過動態選單,未獲取,則需要獲取一次 if (store.getters.dynamicRoutes.length === 0) { if (whiteList.indexOf(to.path) !== -1) { next() } else { getRouter().then(res => { if (res.code === 0) { let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children) store.dispatch('app/dynamicRoutes', menuRouter).then(() => { router.addRoutes(store.getters.dynamicRoutes) next({...to, replace: true}) }) } else { console.log('獲取動態路由失敗!') next({path: '/login'}) } }) } } else { // 路由已存在或已快取路由 if (to.meta.requireAuth) { if (sessionStorage.getItem('loginName') !== null) { // 判斷本地是否存在token next() } else { // 未登入,跳轉到登陸頁面 next({path: '/login'}) } } else { if (whiteList.indexOf(to.path) !== -1) { next() } else { if (sessionStorage.getItem('loginName') !== null) { // 判斷本地是否存在token next(`/?redirect=${to.path}`) } else { next(`/login?redirect=${to.path}`) } } } } } catch (error) { console.log('出錯了') next(`/login?redirect=${to.path}`) } }) router.afterEach(() => { // 在即將進入新的頁面元件前,關閉掉進度條 NProgress.done() })
註釋寫的比較詳細了,主要說下思路:
首先確定獲取動態選單資料的時機。一般在登入成功跳轉到主頁面時,獲取動態選單資料。
如果不採用vuex方式也可以存到sessionStorage裡面,總之就是儲存一下獲取的路由資訊,以免重複獲取。
4接下來看一看,store的寫法
const state = { dynamicRoutes: [] } const mutations = { DYNAMIC_ROUTES (state, routes) { state.dynamicRoutes = routes } } const actions = { dynamicRoutes ({commit}, routes) { commit('DYNAMIC_ROUTES', routes) } }
注意:vue是單頁面應用程式,所以頁面一重新整理資料部分資料也會跟著丟失,所以我們需要將store中的資料儲存到本地,才能保證路由不丟失。
到這裡,動態路由就已經設定好了,總體來說不是很難,主要是有坑!但只要理清了思路,寫起程式碼就會很清晰。
1.首先是component動態匯入的問題,由於webpack的版本不同,需要根據情況來採用import和require方式來匯入,如果匯入不正確多半會報錯,找不到module等等。或者不報錯,但路由跳轉是空白頁。如果匯入正確則一定可以跳轉正常,否則,請查詢正確的匯入方法!路由跳轉正確,能顯示跳轉的元件,就完成了一大半!
2.路由的跳轉的地方,由於我們專案採用的是左側選單欄,有二級選單,所以當路由跳轉正常時,還需確定路由跳轉所渲染的位置是否正確!
在重新整理頁面時遇到一個問題,動態路由表會隨著vuex的重新整理而消失。
處理:這裡在app.vue頁面重新整理時利用sessionStorage儲存一下store,防止重新整理丟失vuex。
如下:
export default { name: 'App', created () { // 在頁面載入時讀取sessionStorage裡的狀態資訊 if (sessionStorage.getItem('storeData')) { this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('storeData')))) } // 在頁面重新整理時將vuex裡的資訊儲存到sessionStorage裡 window.addEventListener('beforeunload', () => { sessionStorage.setItem('storeData', JSON.stringify(this.$store.state)) }) // 相容iphone手機 window.addEventListener('pagehide', () => { sessionStorage.setItem('storeData', JSON.stringify(this.$store.state)) }) } }
另外,在登入成功後也獲取了一下動態路由。這樣處理下來,重新整理時也不會丟失路由了!
// 獲取動態路由 getRouter().then(res => { if (res.code === 0) { let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children) store.dispatch('app/dynamicRoutes', menuRouter).then(() => { router.addRoutes(store.getters.dynamicRoutes) }) console.log(store.getters.dynamicRoutes) } else { console.log('獲取動態路由失敗!') router.push('/login') } })
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45