Vue dynamic routing practice
- Implementation ideas
- Environment introduction
- Implementation process
- Routing data (demo)
🧐🧐🧐 vue dynamic routing (conventional routing), it sounds mysterious 😲 But if you understand the implementation idea, you will find that it is not as difficult as you imagined 😌
Never underestimate your personal strength and potential before you realize your functions yourself😛😛😛😛😛
🔥🔥🔥 Below is the implementation process of a programmer who has just changed from server development to front-end development🔥🔥🔥
Implementation ideas
The idea is actually very simple and clear:
1. Divide routes into static routes and dynamic routes
2. Load normally when static route is initialized
3. After the user logs in, obtain relevant dynamic routing data.
4. Then use vue: addRoute to append to the vue instance.
Although the implementation idea is simple, the process is not smooth, and there are still many details to pay attention to.
Environment introduction
- vue-cli:
- vue: v2.6.11
- vuex: v3.4.0
- vue-router: v3.2.0
Implementation process
- Router file processing (router/):
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeLayout from '../layouts/HomeLayout'
import store from '@/store/index'
Vue.use(VueRouter)
// Solve the bug that reports repeated click routing errors
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err)
}
const routes = [
{
path: '/',
name: 'homeBase',
component: HomeLayout,
redirect: {
name: 'home'
},
children: [
// Portal routing
{
path: 'home',
name: 'home',
component: () => import('../views/portal/'),
},
{
path: 'lists',
name: 'lists',
component: () => import('../views/portal/'),
},
{
path: 'detail',
name: 'detail',
component: () => import('../views/portal/'),
},
]
},
]
// Define static routing collection
const staticRouterMap = [
'home',
'lists',
'detail'
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
// Global interception of routing
// The following can be processed in the intercepting route according to the business logic. Here, only the personal business is shown as an example.
// This example uses vuex+sessionStorage to cooperate with each other to complete the data storage of dynamic routing
// After only storing the dynamic routing information obtained in vuex, the dynamic routing information will be lost when refreshing the page.
// This leads to page 404
router.beforeEach((to, from, next) => {
const userState = JSON.parse(sessionStorage.getItem('userState'))
if (!userState || !userState.isLogin) {
// Not logged in
// If you go to the page without public route, jump to the home page
if (staticRouterMap.indexOf(to.name) < 0) {
next({name: 'home'})
} else {
next()
}
} else {
// Log in
// The route list already exists: Note that the corresponding store data has not been updated when the route is transferred for the first time after logging in.
const hasGetRoute = store.getters['user/hasGetRoute']
const routeMap = JSON.parse(sessionStorage.getItem('routeMap'))
if(!hasGetRoute && routeMap) {
// Refresh the page and have route record data, you can add dynamic routes again
store.dispatch('user/updateRouteOfUser', routeMap)
next({...to, replace: true})
} else {
next()
}
}
})
export default router
- View data processing
<template>
<div class="home">
<div>This is a demo</div>
<div>
<div v-show="!isLogin">
<a-divider>Calling the interface:Simulation login</a-divider>
<div style="margin-top:5px;">
<a-space :size="size">
<a-button type="primary" @click="login()">User login</a-button>
</a-space>
<p>{{loading}}</p>
</div>
</div>
</div>
</div>
</template>
<script>
// @ is an alias to /src
import {
Base64
} from 'js-base64'
import User from '../../api/user'
import {
mapGetters,
mapMutations,
mapActions
} from 'vuex'
export default {
name: 'home',
data() {
return {
size: "middle",
user: {
'name': 'xxxx',
'pass': Base64.encode('xxxx')
},
}
},
components: {},
computed: {
...mapGetters('user', ['isLogin', 'userInfo', 'hasGetRoute'])
},
methods: {
...mapMutations('user', ['setUserState']),
...mapActions('user', ['getUserInfo', 'getDynamicRouteOfUser']),
login() {
if (this.isLogin) {
this.$router.push({
path: '/user'
})
} else {
// Simulate users
User.login(this.user).then(res => {
this.setUserState({
'isLogin': true,
'ut': res.data.user_token,
'userType': 1
})
this.getUserInfo()
//The following is to obtain dynamic routing information based on user login information
this.getDynamicRouteOfUser(type).then(() => {
this.$router.push({
path: '/user'
})
})
}).catch(() => {
})
}
},
},
}
</script>
<style lang="scss" scoped>
.home {
padding: 20px;
}
</style>
- vuex
import VueRouter from '../../router'
import UserApi from '../../api/user'
import axios from 'axios'
import TeacherLayout from '@/layouts/Layout'
import NotFound from '@/layouts/404'
const user = {
namespaced: true,
state: {
// User status related
userState: JSON.parse(sessionStorage.getItem('userState')) || {ut: '', isLogin: false, userType: null},
// Related to user information
userInfo: JSON.parse(sessionStorage.getItem('userInfo')) || {},
// Whether to get route
hasGetRoute: false,
// routeMap
routeMap: JSON.parse(sessionStorage.getItem('routeMap')) || [],
},
getters: {
ut : state => state.userState.ut,
isLogin: state => !!state.userState.isLogin,
userInfo: state => state.userInfo,
hasGetRoute: state => state.hasGetRoute,
routeMap: state => state.routeMap[0].children,
},
mutations: {
setUserState(state, playload) {
state.userState = playload
sessionStorage.setItem('userState', JSON.stringify(state.userState))
},
setUserInfo(state, playload) {
state.userInfo = playload
sessionStorage.setItem('userInfo', JSON.stringify(state.userInfo))
},
setRouteMap(state, routers) {
state.routeMap = routers
// To prevent the dynamically created route from failing to refresh the page, store it locally
sessionStorage.setItem('routeMap', JSON.stringify(routers));
},
setDynamicRouteMap(state, routers) {
state.hasGetRoute = true
let routerMaps = filterRouter(routers)
// Add 404 routes in the end
routerMaps.push({
path: '*',
component: NotFound
})
// Add routes
// This is the point, if you use addRoute directly, it will be invalid
routerMaps.forEach(item => {
VueRouter.addRoute(item);
})
},
resetLogin() {
sessionStorage.clear()
}
},
actions: {
// Get user information
async getUserInfo({commit}) {
await UserApi.user().then(res => {
commit('setUserInfo', res)
}).catch(error => {
console.log(error)
})
},
// Obtain user authorization dynamic routing
async getDynamicRouteOfUser({commit}, type) {
let flag = false
// mock api
mockRouter().then(res => {
commit('setRouteMap', res.data)
commit('setDynamicRouteMap', res.data)
flag = true
}).catch(err => {
console.log(err)
})
return flag
},
// Refresh and reset the route
updateRouteOfUser({commit}, routerMap) {
commit('setDynamicRouteMap', routerMap)
},
}
}
// handle views
const loadView = (viewPath) => {
return () => import('@/views/' + viewPath)
}
// Handle routers
const filterRouter = (routers) => {
return routers.filter((router) => {
// District distribution bureau and view files, because the loading method is different
if (router.component === 'Layout') {
router.component = Layout
}else {
// view
router.component = loadView(router.component)
}
// Delete useless fields in the routing record: This section is negotiated with the background in this example, but is not supported in vue-router. It can be ignored.
if (!router.redirect || !router.redirect.length) { delete router.redirect }
// Determine whether there is a subroutine and call yourself recursively
if(router.children && router.children.length) {
router.children = filterRouter(router.children)
}
return true
})
}
// mock data
async function mockRouter() {
const url = 'http://localhost:8080/'
let routerData
await axios.get(url).then(res => {
routerData = res.data
}).catch(err => {
console.log(err)
})
return routerData
}
export default user;
Routing data (demo)
Contribute to the routing data structure agreed upon by me on the server side, for reference only
{
"data":[
{
"title":"demo",
"name":"x",
"pname":"",
"path": "/x",
"type": 1,
"component": "Layout",
"redirect": {"name": "xx"},
"children": [
{
"title":"child1",
"name":"xx",
"pname":"x",
"path": "",
"type": 2,
"icon": "desktop",
"component": "",
"redirect": {}
},
{
"title":"child1",
"name":"xx",
"pname":"tBase",
"path": "xx",
"type": 2,
"icon": "container",
"component": "",
"redirect": {"name": "xxx"},
"children": [
{
"title":"child2",
"name":"xx",
"pname":"xx",
"path": "xx",
"type": 2,
"icon": "unordered-list",
"component": "",
"redirect": {}
}
]
},
]
}
]
}