VUE3 プロジェクトは動的ルーティングのデモを実装します


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 ルーターのインストール

npm install vue-router

2.4 vuex のインストール

npm install vuex

2.5 インストールストア

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. 開始:

写真の説明を追加してください

おすすめ

転載: blog.csdn.net/qq_22610595/article/details/129599854