Vue router动态路由实现过程

 更新时间:2023年03月14日 09:58:09   作者:Bennett_G  
Vue动态路由(约定路由),听起来好像很玄乎的样子,但是你要是理解了实现思路,你会发现没有想象中的那么难,下面这篇文章主要给大家介绍了关于vue实现动态路由添加功能的简单方法,需要的朋友可以参考下

🧐🧐🧐 vue动态路由(约定路由),听起来好像很玄乎的样子😲 但是你要是理解了实现思路,你会发现,没有想象中的那么难😌

在没有亲自实现功能前,永远不要低估自己的个人实力和潜力😛😛😛

🔥🔥🔥下面是本人一个刚从服务端开发转职前端开发的程序猿的实现过程🔥🔥🔥

实现思路

思路其实很简单,也很明确:

1、将路由分为静态路由(staticRouters)、动态路由

2、静态路由初始化时正常加载

3、用户登陆后,获取相关动态路由数据,

4、然后利用vue:addRoute追加到vue实例中即可。 实现思路虽然很简单,但是过程并不是一帆风顺,需要注意的细节还是很多的

环境介绍

  • vue-cli: v4.x.x
  • vue: v2.6.11
  • vuex: v3.4.0
  • vue-router: v3.2.0

实现过程

路由文件处理(router/index.js):

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeLayout from '../layouts/HomeLayout'
import store from '@/store/index'
Vue.use(VueRouter)
// 解决重复点击路由报错的BUG
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: [
			// 门户路由
			{
				path: 'home',
				name: 'home',
				component: () => import('../views/portal/Home.vue'),
			},
			{
				path: 'lists',
				name: 'lists',
				component: () => import('../views/portal/Lists.vue'),	
			},
			{
				path: 'detail',
				name: 'detail',
				component: () => import('../views/portal/Detail.vue'),	
			},
		]
	},
]
// 定义静态路由集合
const staticRouterMap = [
	'home',
	'lists',
	'detail'
]
const router = new VueRouter({
	mode: 'history',
	base: process.env.BASE_URL,
	routes,
})
// 路由全局拦截
// 以下可根据业务逻辑自行在拦截路由中进行处理,此处仅以本人业务作为示例展示
// 本示例以 vuex+sessionStorage相互配合完成动态路由的数据存储
// 仅以vuex存储获取到的动态路由信息后,在刷新页面时,动态路由信息是会丢失,
// 从而导致页面404
router.beforeEach((to, from, next) => {
	const userState = JSON.parse(sessionStorage.getItem('userState'))
	if (!userState || !userState.isLogin) {
		// 没有登录
		// 如果前往页面非公共路由,则跳转至首页
		if (staticRouterMap.indexOf(to.name) < 0) {
			next({name: 'home'})
		} else {
			next()
		}
	} else {
		// 登录
		// 已经存在路由列表: 注意刚登陆成功第一次调转route时相应store数据还未更新
		const hasGetRoute = store.getters['user/hasGetRoute']
		const routeMap = JSON.parse(sessionStorage.getItem('routeMap'))
		if(!hasGetRoute && routeMap) {
            // 刷新页面且有route记录数据,可再次追加动态路由
			store.dispatch('user/updateRouteOfUser', routeMap)
			next({...to, replace: true})
		} else {
			next()
		}
	}
})
export default router

view数据处理

<template>
	<div class="home">
		<div>
			这是demo
		</div>
		<div>
			<div v-show="!isLogin">
				<a-divider>调用接口: 模拟登陆</a-divider>
				<div style="margin-top:5px;">
					<a-space :size="size">
						<a-button type="primary" @click="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 {
					// 模拟用户
					User.login(this.user).then(res => {
						this.setUserState({
							'isLogin': true,
							'ut': res.data.user_token,
							'userType': 1
						})
						this.getUserInfo()
						//以下就是根据用户登陆信息,获取动态路由信息操作
						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: {
        // 用户状态相关 
        userState: JSON.parse(sessionStorage.getItem('userState')) || {ut: '', isLogin: false, userType: null},
        // 用户信息相关
        userInfo: JSON.parse(sessionStorage.getItem('userInfo')) || {},
        // 是否获取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
            // 为了防止用户刷新页面导致动态创建的路由失效,将其存储在本地中
            sessionStorage.setItem('routeMap', JSON.stringify(routers));
        },
        setDynamicRouteMap(state, routers) {
            state.hasGetRoute = true
            let routerMaps = filterRouter(routers)
            // 最后追加404路由
            routerMaps.push({
                path: '*',
                component: NotFound
            })
            // 追加路由
            // 这块是重点,如果直接使用addRoute是无效的
            routerMaps.forEach(item => {
                VueRouter.addRoute(item);
            })
        },
        resetLogin() {
            sessionStorage.clear()
        }
    },
    actions: {
        // 获取用户信息
        async getUserInfo({commit}) {
            await UserApi.user().then(res => {
                commit('setUserInfo', res)
            }).catch(error => {
                console.log(error)
            })
        },
        // 获取用户授权动态路由
        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
        },
        // 刷新重置路由
        updateRouteOfUser({commit}, routerMap) {
            commit('setDynamicRouteMap', routerMap)
        },
    }
}
// handle views
const loadView = (viewPath) => {
    return () => import('@/views/' + viewPath)
}
// Handle routers
const filterRouter = (routers) => {
    return routers.filter((router) => {
   		// 区分布局与视图文件,因为加载方式不同
        if (router.component === 'Layout') {
            router.component = Layout
        }else {
            // view
            router.component = loadView(router.component)
        }
        // 删除路由记录中的无用字段:这段是本示例与后台协商的,但在vue-router中不被支持的字段信息,可忽略
        if (!router.redirect || !router.redirect.length) { delete router.redirect }
        // 判断是否存在子路由,并递归调用自己
        if(router.children && router.children.length) {
            router.children = filterRouter(router.children)
        }
        return true
    })
} 
// mock 数据
async function mockRouter() {
    const url = 'http://localhost:8080/t.json'
    let routerData
    await axios.get(url).then(res => {
        routerData = res.data
    }).catch(err => {
        console.log(err)
    })
    return routerData
}
export default user;

路由数据(demo)

贡献本人于服务端约定的路由数据结构,仅供参考

{
    "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": "xx.vue",
                    "redirect": {}
                },
                {
                    "title":"child1",
                    "name":"xx",
                    "pname":"tBase",
                    "path": "xx",
                    "type": 2,
                    "icon": "container",
                    "component": "xx.vue",
                    "redirect": {"name": "xxx"},
                    "children": [
                        {
                            "title":"child2",
                            "name":"xx",
                            "pname":"xx",
                            "path": "xx",
                            "type": 2,
                            "icon": "unordered-list",
                            "component": "xx.vue",
                            "redirect": {} 
                        }
                    ]
                },
            ]
        }
    ]
}

到此这篇关于Vue router动态路由实现过程的文章就介绍到这了,更多相关Vue router动态路由内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue3如何监听页面的滚动

    vue3如何监听页面的滚动

    这篇文章主要给大家介绍了关于vue3如何监听页面的滚动的相关资料,在vue中实现滚动监听和原生js无太大差异,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • Vue弹窗的两种实现方式实例详解

    Vue弹窗的两种实现方式实例详解

    这篇文章主要介绍了Vue弹窗的两种实现方式,一种使用.sync修饰符另一种使用v-model,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • 分享几个可以助你提高效率的Vue指令

    分享几个可以助你提高效率的Vue指令

    vue是一款渐进式JavaScript框架,渐进式是指由浅到深,由简单到复杂的使用vue框架,下面这篇文章主要给大家分享介绍了几个可以助你提高效率的Vue指令,需要的朋友可以参考下
    2022-05-05
  • vue中el-tree动态初始默认选中和全选实现方法

    vue中el-tree动态初始默认选中和全选实现方法

    这篇文章主要给大家介绍了关于vue中el-tree动态初始默认选中和全选实现的相关资料,eltree默认选中eltree是一种常用的树形控件,通常用于在网页上呈现树形结构的数据,例如文件夹、目录、组织结构等,需要的朋友可以参考下
    2023-09-09
  • Vue3中emit传值的具体使用

    Vue3中emit传值的具体使用

    Emit是Vue3中另一种常见的组件间传值方式,它通过在子组件中触发事件并将数据通过事件参数传递给父组件来实现数据传递,本文就来介绍一下Vue3 emit传值,感兴趣的可以了解一下
    2023-12-12
  • 深入理解Vue的数据响应式

    深入理解Vue的数据响应式

    Vue.js的核心包括一套“响应式系统”。“响应式”,是指当数据改变后,Vue会通知到使用该数据的代码。例如,视图渲染中使用了数据,数据改变后,视图也会自动更新。
    2021-05-05
  • Vue中this.$router和this.$route的区别及push()方法

    Vue中this.$router和this.$route的区别及push()方法

    这篇文章主要给大家介绍了关于Vue中this.$router和this.$route的区别及push()方法的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • 一文详解如何在Vue3中使用jsx/tsx

    一文详解如何在Vue3中使用jsx/tsx

    本篇文章旨在带领大家快速了解和使用 Vue 中的 JSX 语法,好让大家在 Vue 中遇到或使用 JSX 的时候能很快入手,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • vue定时器设置和关闭页面时关闭定时器方式

    vue定时器设置和关闭页面时关闭定时器方式

    这篇文章主要介绍了vue定时器设置和关闭页面时关闭定时器方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Element Steps步骤条的使用方法

    Element Steps步骤条的使用方法

    这篇文章主要介绍了Element Steps步骤条的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07

最新评论