In this article, we will mainly talk about login and dynamic loading of components.
Login status saved
When the user logs in successfully, the current user's login information needs to be saved locally for later use. The specific implementation is as follows:
Log in to save data successfully
After the login operation is successfully executed, the data is submitted to the store through the commit operation. The core code is as follows:
('/login', { username: , password: }).then(resp=> { if (resp && == 200) { var data = ; _this.$('login', ); var path = _this.$; _this.$({path: path == '/' || path == undefined ? '/home' : path}); } });
store
The core code of the store is as follows:
export default new ({ state: { user: { name: ('user' || '[]') == null ? 'Not logged in' : (('user' || '[]')).name, userface: ('user' || '[]') == null ? '' : (('user' || '[]')).userface } }, mutations: { login(state, user){ = user; ('user', (user)); }, logout(state){ ('user'); } } });
In order to reduce the hassle, the data after the user login is successfully saved in localStorage (preventing the data loss after the user presses F5 to refresh), and is stored in the form of a string, and then converted to json when fetched. When the user logs out of login, the data in localStorage is cleared.
Dynamic component loading
In the permission management module, this is the core of the front-end.
Core idea
After the user logs in successfully, before entering the home home page, he sends a request to the server, requiring the current menu information and component information to be obtained. The server returns a json string based on the roles that the current user has and the resources corresponding to the role, and the format is as follows:
[ { "id": 2, "path": "/home", "component": "Home", "name": "Employee Information", "iconCls": "fa fa-user-circle-o", "children": [ { "id": null, "path": "/emp/basic", "component": "EmpBasic", "name": "Basic Information", "iconCls": null, "children": [], "meta": { "keepAlive": false, "requireAuth": true } }, { "id": null, "path": "/emp/adv", "component": "EmpAdv", "name": "Advanced Information", "iconCls": null, "children": [], "meta": { "keepAlive": false, "requireAuth": true } } ], "meta": { "keepAlive": false, "requireAuth": true } } ]
After the front-end gets this string, it does two things: 1. Dynamically add json to the current route; 2. Save the data to the store, and then each page renders the menu based on the data in the store.
The core idea is not difficult, let’s take a look at the implementation steps below.
Data request timing
This is very important.
Some friends may say that this is difficult, isn’t it enough to just request after logging in successfully? Yes, after logging in, it is OK to request menu resources. After the request is reached, we save it in the store for the next use, but there will be another problem. If the user logs in successfully, clicks on a certain subpage, enters the subpage, and then presses F5 to refresh, then it will be GG, because after F5 is refreshed, the data in the store is gone, and we only requested menu resources once when logging in successfully. To solve this problem, there are two ideas: 1. Do not save the menu resources in the store, but save them to localStorage, so that the data is still there after F5 is refreshed; 2. Load the menu resources once directly in the mounted method of each page.
Since menu resources are very sensitive, it is best not to save them locally, so plan 1 is abandoned, but plan 2 has a bit of workload, so I took a way to simplify it, and the method I took was to use the navigation guards in the route.
Routing Navigation Guard
My specific implementation is like this. First, create a routes array in the store, which is an empty array, and then enable the routing global guard, as follows:
((to, from, next)=> { if ( == 'Login') { next(); return; } var name = ; if (name == 'Not logged in') { if ( || == null) { next({path: '/', query: {redirect: }}) } else { next(); } } else { initMenu(router, store); next(); } } )
The code here is very short, let me give you a simple explanation:
1. If the page you are going to is the login page, there is nothing to say about this, just go through it.
2. If it is not a login page, I first get the current login status from the store. If I am not logged in, I will use the requiredAuth attribute of the meta attribute in the route to determine whether the page to be visited needs to be logged in. If I need to log in, I will jump back to the login page. At the same time, the path of the page to be visited is passed as a parameter to the login page, so that I can jump to the target page after the login is successful. If I do not need to log in, I will pass it directly (in fact, only the Login page in this project does not require login); if I have logged in, the menu will be initialized first and then jumped.
The operation of the initialization menu is as follows:
export const initMenu = (router, store)=> { if ( > 0) { return; } getRequest("/config/sysmenu").then(resp=> { if (resp && == 200) { var fmtRoutes = formatRoutes(); (fmtRoutes); ('initMenu', fmtRoutes); } }) } export const formatRoutes = (routes)=> { let fmRoutes = []; (router=> { let { path, component, name, meta, iconCls, children } = router; if (children && children instanceof Array) { children = formatRoutes(children); } let fmRouter = { path: path, component(resolve){ if (("Home")) { require(['../components/' + component + '.vue'], resolve) } else if (("Emp")) { require(['../components/emp/' + component + '.vue'], resolve) } else if (("Per")) { require(['../components/personnel/' + component + '.vue'], resolve) } else if (("Sal")) { require(['../components/salary/' + component + '.vue'], resolve) } else if (("Sta")) { require(['../components/statistics/' + component + '.vue'], resolve) } else if (("Sys")) { require(['../components/system/' + component + '.vue'], resolve) } }, name: name, iconCls: iconCls, meta: meta, children: children }; (fmRouter); }) return fmRoutes; }
In the initialization menu, first determine whether the data in the store exists. If it exists, it means that this jump is a normal jump, rather than entering by the user pressing F5 or directly entering a certain address in the address bar. Otherwise, go to load the menu. After getting the menu, first use the formatRoutes method to convert the json returned by the server to the format required by the router. Here we mainly convert the component, because the component returned by the server is a string, while the component required in the router is a component. Therefore, we can dynamically load the required components in the formatRoutes method. After the data format is successfully prepared, on the one hand, the data is stored in the store, and on the other hand, it is dynamically added to the route using the addRoutes method in the route.
Menu Rendering
Finally, in the Home page, get the menu json from the store and render it into a menu. The relevant code can be viewed in it, and will not be described in detail.
OK, after this, different users can see different menus after logging in successfully.