web123456

vue-router dynamic routing practice

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

  1. 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
  1. 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>
  1. 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": {} 
                        }
                    ]
                },
            ]
        }
    ]
}