VUE3项目实现动态路由demo

Posted 夜间沐水人

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VUE3项目实现动态路由demo相关的知识,希望对你有一定的参考价值。

文章目录


1、创建vue项目

vue create orkasgb-vue3-app

2、安装常用的依赖

2.1 安装elementUI

npm install element-plus --save

2.2 安装axios

npm i --save axios

2.3 安装router

npm install vue-router

2.4 安装vuex

npm install vuex

2.5 安装store

npm install store

2.6 安装mockjs

// -D表示在开发环境中使用
npm install mockjs -D 

3、编写登录页面以及逻辑

编写登录页面

登录逻辑实现:

/**
* 登录
*/
submitForm() 
	this.$refs["elForm"].validate((valid) => 
		if (!valid) return;
		// 请求后台,验证登录信息
		this.$axios
		.post("/test/api/login", "")
		.then((resp) => 
			if (resp.status == "200" && resp.data &&
				resp.data.code == "200" && resp.data.data.legth != 0) 
					// 登录成功后,用户信息缓存
					localStorage.setItem("UserInfor", JSON.stringify(resp.data.data));
					window.sessionStorage.setItem(
					"UserInfor",
					JSON.stringify(resp.data.data)
					);
					this.$message.info(resp.data.message);
					// 登录成功后,缓存token
					this.$store.commit("setToken", resp.data.data.token);
					window.sessionStorage.setItem("token", resp.data.data.token);
					// 登录成功后,跳转到home页
					this.$router.replace("/home");
			 else 
				this.$message.error("登录失败!");
			
		);
	);

4、编写首页以及逻辑

首页布局:

逻辑:

// 数据来源配置
data() 
	return 
		formData: 
			userInfor: window.sessionStorage.getItem("UserInfor"), // 获取用户信息,直接从sessionStorage中获取,在登录的时候已经保存在sessionStorage中
		
	;
,

/**
* 左侧菜单栏,直接通过监听路由,开启el-menu组件中路由模式实现
*/
// 开启el-menu组件中路由模式
<el-menu router="true"></el-menu>
// computed方法可以不断的监听路由变化,并当路由有变化时返回路由,并且computed方法是由缓存的,比watch性能好
computed: 
	routers() 
		return this.$store.state.routes;
	,
,

/**
* 退出登录
*/
loginOut() 
	// 退出登录时,删除缓存的用户信息
	localStorage.removeItem("UserInfor");
	// 退出登录时,删除缓存的token
	this.$store.commit("delToken", "token");
	// 退出登录时,删除缓存的路由
	this.$store.commit("initRouters", []);
	// 退出登录时,跳转到登录页面
	this.$router.replace("/");

5、配置router.js

import  createRouter, createWebHashHistory  from 'vue-router'
/**
* 设置固定的路由,一般是登录页面的路由是固定的
*/
const routes = [
	
		path: "/",
		name: "login",
		component: () => import("../components/LoginPage.vue")
	,
	
		path: "/home",
		name: "home",
		component: () => import("../components/HomePage.vue")
	
];

/**
* 路由配置,比如设置路由模式为hash
*/
const router = createRouter(
	history: createWebHashHistory(),
	routes
);

export default router;

6、配置store.js

import Vuex from 'vuex'
/**
* vuex是一个状态管理器,比如我们的一些项目信息可以用vuex来管理。
*/
export default new Vuex.Store(
state: 
	routes: [],// 缓存动态路由
	token: '' // 缓存token
	,

// 同步执行。
mutations: 
	// 初始化动态路由
	initRouters(state, data) 
	state.routes = data;
	,

// 设置token
setToken(state, token) 
	state.token = token
	sessionStorage.token = token
	,

// 删除token
delToken(state) 
	state.token = ''
	sessionStorage.removeItem('token')
	
,

// 异步执行
actions: 
)

7、配置menuUtils.js(动态路由重点)

import axios from 'axios'
/**
* 初始化菜单,从后台获取动态菜单
*
* @param 登录ID logId
* @param 路由 router
* @param 缓存 store
*/
const initMenu = function (logId, router, store) 
	axios.post("/test/api/menu",  logId: logId ).then((resp) => 
		console.log(resp);
		if (resp.status == "200" && resp.data && resp.data.code == "200" && resp.data.data.legth != 0) 
			// 动态路由请求成功后,将路由格式化成vue能识别的路由形式
			var fmtRouters = formatRouters(resp.data.data);
			
			// 将格式化好的路由添加到router中
			fmtRouters.forEach(fmtRouter => router.addRoute(fmtRouter));
			
			// 缓存格式化好的路由
			store.commit('initRouters', fmtRouters);
		
	);


/**
* 格式化动态路由
*
* @param menus 动态路由
*/
const formatRouters = (menus) => 
	if (menus.legth == 0) 
		return;
	

	let fmtRouters = [];
	menus.forEach(menu => 
		let name, path, compent, children = menu;
	
		// 递归格式化children路由
		if (children && children instanceof Array) 
			children = formatRouters(children);
		
	
		let fmtRouter = 
			name: name,
			path: '/' + path,
			// 重点,从后台返回的component实际上的一个字符串,vue不认识,需要转化成vue能认识的component,才能跳转页面
			component: () => import(`@/components/$compent.vue`), 
			children: children
		;
	
		fmtRouters.push(fmtRouter);
	);

	return fmtRouters;


export default initMenu;

8、配置main.js

import  createApp  from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import  ElMessage  from 'element-plus'
// 导入elementUI图标
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// 导入elementUI样式
import 'element-plus/dist/index.css'
// 导入路由
import router from './router/router'
// 导入store缓存
import store from './store/sotre';
// 导入axios,用于发送请求
import axios from 'axios'
// 导入vuex,状态管理
import Vuex from 'vuex'
// 导入自定义的菜单工具
import initMenu from './utils/menuUtils'
// 导入mock
import './mock/mock'

const app = createApp(App);
app.use(ElementPlus)
app.use(router)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) 
	app.component(key, component)


// 设置全局侗剧,比如在组件中可以使用this.$axios等
app.config.globalProperties.$axios = axios;
app.config.globalProperties.$store = store;
app.config.globalProperties.$message = ElMessage;
app.config.globalProperties.$vuex = Vuex;
app.mount('#app')

/**
* 路由守卫,每一次路由跳转都会进入这里。
*/
router.beforeEach((to, from, next) => 

	// 如果token不存在,也就是没登录,那么直接跳转到登录页
	const token = window.sessionStorage.getItem("token");
	if (null == token || !token || token.length == 0) 
		next();
		return;
	

	// 如果token存在,就说明登录成功,去初始化菜单
	initMenu("toney", router, store);
	next();
);

9、编写mock.js

import Mock from 'mockjs'

/**
* 登录验证
*/
Mock.mock("/test/api/login","post",(options)=>
	console.log("mock--/test/api/login",options)
	return Mock.mock("code":"200","message":"登录成功","data|1":["id|+1":334,"name":"@cname","logId":"toney","image":"@image","token":"YUGXSIBXISBXI468327943849OONONON"])
)

/**
* 获取动态路由
*/
Mock.mock("/test/api/menu","post",(options)=>
	console.log("mock--/test/api/menu",options)
	return Mock.mock("code":"200","message":"初始化菜单菜单成功!","data":["id|+1":100000247,"userId":"1","name":"home","path":"home","compent":"HomePage","children":["id|+1":100000247,"userId":"1","name":"name1","path":"compent1Page","compent":"Compent1Page","id|+1":100000247,"userId":"2","name":"name2","path":"compent2Page","compent":"Compent2Page","id|+1":100000247,"userId":"2","name":"name3","path":"compent3Page","compent":"Compent3Page","id|+1":100000247,"userId":"2","name":"name4","path":"compent4Page","compent":"Compent4Page","id|+1":100000247,"userId":"1","name":"name5","path":"compent5Page","compent":"Compent5Page","id|+1":100000247,"userId":"2","name":"name6","path":"compent6Page","compent":"Compent6Page"]])
)

Mock.setup(timeout:300)

10、项目结构

11、启动:

vue项目实现动态路由和动态菜单搭建插件式开发框架免费源码

参考技术A 以往我们在开发vue项目的时候,总是通过将路径和路由写在route/index.js文件中,然后直接进行访问即可,一般实现权限匹配都是通过菜单下面的权限参数和路由守卫进行一个验证拦截和权限匹配,然而这样安全性仍然不足。因为我们在route/index.js中已经写满了所有的路由,这样子不仅造成静态路由内容过多、修改困难,同时当静态路由内容过多的时候,我们在路由中的内容就显得极其复杂。

而后端对前端的控制也显得较为无力,无法实现严格性的控制。

由此我们发现通过动态路由控制是必然的,此时我们只需要通过后端获取数据菜单和路由信息json,然后动态添加路由并生成菜单,使菜单与动态路由内容进行一个匹配,这样子我们可以实现由后端控制前端的菜单和路由,我们的项目往往只需要内置几个组件无需权限的公共页面如登陆、注册、忘记密码和404错误这几个常用页面组件。

我们只需要将写好的组件放置到我们的view视图下,然后我们通过动态的路由和菜单实现路由添加和菜单进行匹配,我们便可实现对插件进行访问,我们减少了对route/index.js内容写入,同时也有利于减少内存的占用。

我们通过动态路由的形式,我们生成的菜单权限更加的完善,不仅实现依靠菜单与路由守卫拦截实现鉴权,也可以通过动态路由实现动态加载vue文件,控制更加深度

我们通过动态路由的形式,我们可以将项目分给不同的人进行完成,便于组建一个开发团队,因为他们所开发的组件,我们只需要在具备基本的javascript库的情况下。我们直接进行动态路由的一个挂载和菜单生成便可完成项目合作,减少了对route/index.js文件的操作,保证项目的完整性。

最后我发现在非node环境的开发条件下,我们可以实现远程的vue文件加载,这不仅为我们开发提供了便利,同时也有利于我们及时修改文件,以达到项目的需求,更有利于保障安全,实现服务器vue文件加载。

Vue:2.6.11。

Vue-route:3.2.0。

主页

聊天

第一通过后端返回的一个路由json数据,我们通过前端生成符合路由路由静态内容数组的一个数组,然后再通过addRoute进行一个循环添加,我们以此生成动态路由。在登陆时获取后端返回的菜单信息,我们进行菜单的一个循环生成,由此我们的一个动态项目就已经完成。

第二怎样对动态路由和菜单项目进行一个管理。

我们首先可以通过搭建一个组件通过添加路由信息和管理菜单实现二者的动态匹配。我们只需要对路由信息进行一个添加和修改,并和菜单相互间进行匹配,我们便可实现简单的路由挂载。

组件管理

菜单管理

此时将数据提交的后端由后端进行数据保存,我们此时的组件只需要放在views文件夹下,添加路由进行文件加载,我们便可实现路由管理。

第一登陆页面配置。

我们需要在静态文件夹下创建一个menu.json和route.json。两个json文件模拟服务器登录时返回的数据。

我们在登录页面模拟获取数据之后,我们通过菜单的一个方法进行生成菜单,通过路由的方法生成路由数组并进行循环添加,然后执行路由跳转。

第二配置路由初始化内容。我们将route/index.js的路由信息填为空是非常不理智的,而且会报错,因为路由初始化在加载前已经完成。有些页面完全不需要权限便可访问,比如登录、注册、找回密码和404错误,这种不需要权限的页面,我们还是需要将其直接以静态的形式写在route/index.js文件中。

Index初始数据

import Vue from 'vue'

import VueRouter from 'vue-router'

Vue . use ( VueRouter )

const routes = [

path: '/' , //访问url

name: 'login' , //路由名称

component : () => import ( '@/unitui/pages/Login.vue' ), //加载模板文件

meta:

show_site: 0 , //是否全屏显示

web_title: "登录" //网站标题



,



path: '/register' , //访问url

name: 'register' , //路由名称

component : () => import ( '@/unitui/pages/Register.vue' ), //加载模板文件

meta:

show_site: 0 , //是否全屏显示

web_title: "注册" //网站标题



,



path: '/forget' , //访问url

name: 'forget' , //路由名称

component : () => import ( '@/unitui/pages/Forget.vue' ), //加载模板文件

meta:

show_site: 0 , //是否全屏显示

web_title: "找回密码" //网站标题



,



path: '/404' , //访问url

name: '404' , //路由名称

component : () => import ( '@/unitui/pages/404.vue' ), //加载模板文件

meta:

show_site: 0 , //是否全屏显示

web_title: "404错误" //网站标题



,

]

const router = new VueRouter (

routes

)

router . beforeEach (( to , from , next ) =>

document . title = to . meta . web_title

console . log ( to );

next ()

)

export default router

第三,关于防止刷新后丢失的问题。我们需要在app.vue文件中的methods方法中定义一个路由生成方法。

示例:

init_route () //初始化路由,防止刷新丢失

if ( sessionStorage . getItem ( "route_data" ) != null ) //只有后端已经返回数据的情况下才允许生成

const route_data = JSON . parse ( sessionStorage . getItem ( "route_data" )); //获取路由信息

const data = []; //默认路由数组

for ( let index = 0 ; index < route_data . length ; index ++) //生成路由信息

data [ index ] =

path: route_data [ index ]. path , //访问url

name: route_data [ index ]. name , //路由名称

component : resolve =>

require ([ `@/views/ $ route_data [ index ]. component ` ], resolve ), //加载模板文件

meta:

show_site: route_data [ index ]. meta . show_site , //是否全屏显示

web_title: route_data [ index ]. meta . web_title //网站标题



;



for ( let index = 0 ; index < data . length ; index ++) //循环添加路由

this . $router . addRoute ( data [ index ]);







在mounted中进行方法调用,防止刷新的时路由丢失,导致发生错误。该方法内容基本和登陆页面的菜单出路由初始内容基本相同,但我们唯一差别的是,我们需要判断登陆所获取的路由信息是否存在,只有在存在的时候及后端已经返回了路由信息,即证明登录成功的时候,我们才会动态添加路由。

第一在刷新之后,默认跳转到path:’*’的一个路由界面中去,此时我们解决方法只需要将path:’*’路由进行一个删除,将其删除就变可正常访问。

第二动态路由跳转时发生Cannot find module xxx错误。

意思是无法加载我们指定的一个vue文件,这是由于route3.0版本后import方式不支持传入变量,此时我们只需要将其改为require方式便可。

我们此次动态vue项目开发已经基本完成,我的开发的项目是基于element-ui进行,那么如果你需要源码参考。可以私信回复unit便可获取。

以上是关于VUE3项目实现动态路由demo的主要内容,如果未能解决你的问题,请参考以下文章

vue3动态路由及菜单

VUE3项目实现动态路由demo

Vue3+elemetPlus支持动态路由和菜单管理UI框架

Vue3动态路由(Vite+Vue3+TS+Mock)

vue项目 动态路由怎么做

基于vscode开发vue3项目的详细步骤教程 3 前端路由vue-router