文章目录
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})