您好,登錄后才能下訂單哦!
本文我們主要來聊聊登錄以及組件的動態加載。
登錄狀態保存
當用戶登錄成功之后,需要將當前用戶的登錄信息保存在本地,方便后面使用。具體實現如下:
登錄成功保存數據
在登錄操作執行成功之后,通過commit操作將數據提交到store中,核心代碼如下:
this.postRequest('/login', { username: this.loginForm.username, password: this.loginForm.password }).then(resp=> { if (resp && resp.status == 200) { var data = resp.data; _this.$store.commit('login', data.msg); var path = _this.$route.query.redirect; _this.$router.replace({path: path == '/' || path == undefined ? '/home' : path}); } });
store
store的核心代碼如下:
export default new Vuex.Store({ state: { user: { name: window.localStorage.getItem('user' || '[]') == null ? '未登錄' : JSON.parse(window.localStorage.getItem('user' || '[]')).name, userface: window.localStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.localStorage.getItem('user' || '[]')).userface } }, mutations: { login(state, user){ state.user = user; window.localStorage.setItem('user', JSON.stringify(user)); }, logout(state){ window.localStorage.removeItem('user'); } } });
為了減少麻煩,用戶登錄成功后的數據將被保存在localStorage中(防止用戶按F5刷新之后數據丟失),以字符串的形式存入,取的時候再轉為json。當用戶注銷登陸時,將localStorage中的數據清除。
組件動態加載
在權限管理模塊中,這算是前端的核心了。
核心思路
用戶在登錄成功之后,進入home主頁之前,向服務端發送請求,要求獲取當前的菜單信息和組件信息,服務端根據當前用戶所具備的角色,以及角色所對應的資源,返回一個json字符串,格式如下:
[ { "id": 2, "path": "/home", "component": "Home", "name": "員工資料", "iconCls": "fa fa-user-circle-o", "children": [ { "id": null, "path": "/emp/basic", "component": "EmpBasic", "name": "基本資料", "iconCls": null, "children": [], "meta": { "keepAlive": false, "requireAuth": true } }, { "id": null, "path": "/emp/adv", "component": "EmpAdv", "name": "高級資料", "iconCls": null, "children": [], "meta": { "keepAlive": false, "requireAuth": true } } ], "meta": { "keepAlive": false, "requireAuth": true } } ]
前端在拿到這個字符串之后,做兩件事:1.將json動態添加到當前路由中;2.將數據保存到store中,然后各頁面根據store中的數據來渲染菜單。
核心思路并不難,下面我們來看看實現步驟。
數據請求時機
這個很重要。
可能會有小伙伴說這有何難,登錄成功之后請求不就可以了嗎?是的,登錄成功之后,請求菜單資源是可以的,請求到之后,我們將之保存在store中,以便下一次使用,但是這樣又會有另外一個問題,假如用戶登錄成功之后,點擊某一個子頁面,進入到子頁面中,然后按了一下F5進行刷新,這個時候就GG了,因為F5刷新之后store中的數據就沒了,而我們又只在登錄成功的時候請求了一次菜單資源,要解決這個問題,有兩種思路:1.將菜單資源不要保存到store中,而是保存到localStorage中,這樣即使F5刷新之后數據還在;2.直接在每一個頁面的mounted方法中,都去加載一次菜單資源。
由于菜單資源是非常敏感的,因此最好不要不要將其保存到本地,故舍棄方案1,但是方案2的工作量有點大,因此我采取辦法將之簡化,采取的辦法就是使用路由中的導航守衛。
路由導航守衛
我的具體實現是這樣的,首先在store中創建一個routes數組,這是一個空數組,然后開啟路由全局守衛,如下:
router.beforeEach((to, from, next)=> { if (to.name == 'Login') { next(); return; } var name = store.state.user.name; if (name == '未登錄') { if (to.meta.requireAuth || to.name == null) { next({path: '/', query: {redirect: to.path}}) } else { next(); } } else { initMenu(router, store); next(); } } )
這里的代碼很短,我來做一個簡單的解釋:
1.如果要去的頁面是登錄頁面,這個沒啥好說的,直接過。
2.如果不是登錄頁面的話,我先從store中獲取當前的登錄狀態,如果未登錄,則通過路由中meta屬性的requireAuth屬性判斷要去的頁面是否需要登錄,如果需要登錄,則跳回登錄頁面,同時將要去的頁面的path作為參數傳給登錄頁面,以便在登錄成功之后跳轉到目標頁面,如果不需要登錄,則直接過(事實上,本項目中只有Login頁面不需要登錄);如果已經登錄了,則先初始化菜單,再跳轉。
初始化菜單的操作如下:
export const initMenu = (router, store)=> { if (store.state.routes.length > 0) { return; } getRequest("/config/sysmenu").then(resp=> { if (resp && resp.status == 200) { var fmtRoutes = formatRoutes(resp.data); router.addRoutes(fmtRoutes); store.commit('initMenu', fmtRoutes); } }) } export const formatRoutes = (routes)=> { let fmRoutes = []; routes.forEach(router=> { let { path, component, name, meta, iconCls, children } = router; if (children && children instanceof Array) { children = formatRoutes(children); } let fmRouter = { path: path, component(resolve){ if (component.startsWith("Home")) { require(['../components/' + component + '.vue'], resolve) } else if (component.startsWith("Emp")) { require(['../components/emp/' + component + '.vue'], resolve) } else if (component.startsWith("Per")) { require(['../components/personnel/' + component + '.vue'], resolve) } else if (component.startsWith("Sal")) { require(['../components/salary/' + component + '.vue'], resolve) } else if (component.startsWith("Sta")) { require(['../components/statistics/' + component + '.vue'], resolve) } else if (component.startsWith("Sys")) { require(['../components/system/' + component + '.vue'], resolve) } }, name: name, iconCls: iconCls, meta: meta, children: children }; fmRoutes.push(fmRouter); }) return fmRoutes; }
在初始化菜單中,首先判斷store中的數據是否存在,如果存在,說明這次跳轉是正常的跳轉,而不是用戶按F5或者直接在地址欄輸入某個地址進入的。否則就去加載菜單。拿到菜單之后,首先通過formatRoutes方法將服務器返回的json轉為router需要的格式,這里主要是轉component,因為服務端返回的component是一個字符串,而router中需要的卻是一個組件,因此我們在formatRoutes方法中動態的加載需要的組件即可。數據格式準備成功之后,一方面將數據存到store中,另一方面利用路由中的addRoutes方法將之動態添加到路由中。
菜單渲染
最后,在Home頁中,從store中獲取菜單json,渲染成菜單即可,相關代碼可以在Home.vue中查看,不贅述。
OK,如此之后,不同用戶登錄成功之后就可以看到不同的菜單了。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。