VUE3项目实现动态路由demo

时间:2022-12-28 01:20:33


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、编写登录页面以及逻辑

编写登录页面
VUE3项目实现动态路由demo

登录逻辑实现:

/**
* 登录
*/
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、编写首页以及逻辑

首页布局:
VUE3项目实现动态路由demo

逻辑:

// 数据来源配置
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、项目结构

VUE3项目实现动态路由demo

11、启动:

VUE3项目实现动态路由demo