(1)项目介绍
(2)创建项目
(3)项目结构介绍
(4)登录页面的编写
(5)处理登陆事件
(6)配置相应拦截器
(7)配置请求转发解决跨域
(8)登录成功跳转页面
(9)导航栏功能实现
(10)安装Vuex
(11)封装菜单请求工具类
(13)路由导航守卫介绍
(14)菜单功能完整实现
(15)获取用户信息功能实现
(1)项目介绍
为什么要学习云E办呢?
因为受今年疫情的影响,很多企业从之前的线下办公,转到线上办公,线上办公页一度成为了微博的热搜词,可见线上办公热度也是非常高的。线上办公的人数增多,我们也发现了线上办公的优点,比如说可以实现办公流程的自动化,节省企业办公费用,实现绿色办公,同时呢也可以去提高我们的工作效率…由于这些优点,线上办公已经成为了当今的一个主流趋势。
我们的项目主要目的是为了实现中小型企业的在线办公系统,是用来管理日常办公事务的一个系统,能够管理的内容非常的多,比如说:日常的各种流程的审批呀,公告啊,财务,人事,资产,行政,项目移动办公等等…最主要的一个作用是通过以软件的形式,让我们办公系统更加方便管理,更加简单,高效规范,能够提高管理运营水平,就想我们的项目名字一样,让我们的办公更容易。
这个项目在技术方面采用了最主流前后端分离开发的模式,后端采用SpringBoot MVC MyBatis-plus 安全框架用了Spring Security

基本Vue全家桶
项目搭建:vue-cli
状态管理:Vuex
路由:VueRouter
UI界面:elementUI
通讯框架:Axios
前端语法:ES6
打包:Webpack
在线聊天:WebSocket
字体:font-awesome
文件上传下载:js-file-download
在线聊天开源项目:vue-chat
(2)创建项目
首先下载Node.js:

之后:

安装vue-cli:下面是新版本的安装办法:

查看是否安装成功:

创建项目:使用Windows PowerShell搭建项目

进入一个目录创建yeb项目

如果出现问题:运行命令
不使用骨架,我们手动去选,选择第二项

选择一些东西:先选择这两个

下面直接选择:no


创建完成:
启动项目:

启动成功

浏览器可以正常访问:

(3)项目结构介绍
我们这里使用WebStorm进行打开编辑,也可以使用IDEA,但是需要安装一个插件vue.js就可以了

第一个目录是整个项目用的依赖:可以通过npm install 去安装依赖了

public目录:有一个图标,一个index.html:它相当于是项目的入口,可以理解为首页,或模板页,在实际开发中用不到,因为vue的话开发出来的叫做单页面应用,就一个html的页面,剩下的叫做组件
这个项目是单页面应用,所以有一个index.html,只是作为模板页,在开发中用不到,真正的入口在main.js

src:是项目的原码目录
assets:放一些资源的 component:组件目录 router:路由的目录(在创建项目的时候选了路由,所以这里有这个目录)views:页面目录
main.js:整个程序的入口了 import是ES6的语法,当被babel打包的时候转成ES5的语法,ES5是reequire
Vue.config.productionTip = false :关闭浏览器对应的提示 当为true的时候,会开启提示:

render: h => h(App) :是渲染我们对应的组件
.$mount('#app'):是手动挂和之前通过el:‘#app‘ 是一样的

.gitgnore:git的忽略的配置文件
bable.config.js:是babel的配置文件,主要是将ES6的语法转换成ES5
README.md:项目说明

package.json:项目的配置文件
scrips下面是封装的常用的命令 向server启动服务啊 build:构建 他们都是可以直接去运行的 小路三角
dependercies:正式环境用到的依赖
devDependencies:开发环境用到的依赖

配置一下启动项目:


(4)登录页面的编写
vue是关注度分离的,所以没办法提供UI的操作,需要安装ElementUI

安转完之后,package.json:多个elementUI

引入到项目中去使用:main.js

修改一下App.vue:
- "app">
-
-
-
-
-
删除这两个组价:


在views目录下创建Login.vue组件:

配置路由:

- import Vue from 'vue'
- import VueRouter from 'vue-router'
- import Login from "@/views/Login";
-
- Vue.use(VueRouter)
-
- const routes = [
- {
- //加载斜杠,会找到Login
- path: '/',
- name: 'Login',
- component: Login
- },
-
- ]
-
- const router = new VueRouter({
- routes
- })
-
- export default router
Login.vue:
-
-
"rules" ref="loginForm" :model="loginForm" class="loginContainer"> -
"loginTitle">系统登录
-
"username"> -
"text" auto-complete="false" v-model="loginForm.username" placeholder="请输入用户名"> -
-
-
"password"> -
"text" auto-complete="false" v-model="loginForm.password" placeholder="请输入密码"> -
-
-
"code"> -
"text" auto-complete="false" v-model="loginForm.code" placeholder="点击图片更换验证码" style="width:250px;margin-right: 5px"> -
"captchaUrl"> -
-
-
"checked" calss="loginRemember">记住我 -
"primary" style="width: 100%">登录 -
-
-
-
-
-
- export default {
- name: "Login",
- data(){
- return{
- loginForm:{
- username:'admin',
- password:'123',
- code:''
- },
- checked:true
- }
- }
- }
-
- .loginContainer {
- border-radius: 15px;
- background-clip: padding-box;
- margin: 180px auto;
- width: 350px;
- padding: 15px 35px 15px 35px;
- background: #fff;
- border: 1px solid #eaeaea;
- box-shadow: 0 0 25px #cac6c6;
- }
-
- .loginTitle {
- margin: 0 auto 40px auto;
- text-align: center;
- color: #505458;
- }
-
- /*.loginRemember {
- text-align: left;
- margin: 0px 0px 15px 0px;
- }*/
-
- .el-form-item__content {
- display: flex;
- align-items: center;
- }

(5)处理登陆事件
首先去校验一下用户明密码不能为空,添加校验规则:
添加@click

添加 :rules=“rules”


(6)配置相应拦截器
下面需要调用后端的接口,去实现相关的 功能,那怎么去调呢?Vue注重关注度分离原则的,Vue框架并没有通讯的能力,提倡使用Axios框架进行通信
安装Axios

在package.json:里面加入了axios:

下面就可以写我们的请求了,比如说在登录这一块直接通过axios去调用后端的接口,然后进行相应的返回,仅进行处理,那么每一个事件需要调用后端接口,都需要写axios框架,有一个问题,你这个请求有可能成功有可能失败,成功有成功的处理方法,失败有失败的处理方法,也就是说每一个调用后端接口的方法,都要去判断你的请求是否成功或者失败,每一个地方都要去做,过于麻烦了,这个时候我们可以把它封装起来,用统一的响应拦截器,判断它是否成功或者失败,失败的话把它提示出来,省略了响应的处理了:
创建目录utils 创建配置 api.js:



- import axios from 'axios'
- //导入elemenui的提示信息
- import {Message} from "element-ui";
- import router from '../router'
- import Vue from 'vue'
-
- axios.defaults.baseURL = '/'
- Vue.prototype.axios = axios
-
- // 请求拦截器
- axios.interceptors.request.use(config=>{
- if (window.sessionStorage.getItem('tokenStr')) {
- //请求携带自定义token
- config.headers['Authorization'] =
- window.sessionStorage.getItem('tokenStr');
- }
- return config
- },error => {
- console.log(error);
- })
-
- //响应拦截器 请求的统一的处理
- axios.interceptors.response.use(success => {
- //业务逻辑错误 成功调到接口返回响应码200
- if (success.status && success.status == 200) {
- //后端返回的 code
- if (success.data.code == 500 || success.data.code == 401 ||
- success.data.code == 403) {
- //输出返回响应信息
- Message.error({message: success.data.message});
- return;
- }
- //后端返回响应信息
- if (success.data.message) {
- Message.success({message: success.data.message});
- }
- }
- return success.data;
- //error表示没有调到后端接口
- }, error => {
- if (error.response.code == 504 || error.response.code == 404) {
- Message.error({message: '服务器被吃了o(╯□╰)o'});
- } else if (error.response.code == 403) {
- Message.error({message: '权限不足,请联系管理员!'});
- } else if (error.response.code == 401) {
- Message.error({message: '尚未登录,请登录'});
- router.replace('/');
- } else {
- if (error.response.data.message) {
- Message.error({message: error.response.data.message});
- } else {
- Message.error({message: '未知错误!'});
- }
- }
- return;
- });
-
- let base = '';//访问地址后来可能加的东西,如果需要加的话直接修改base
-
- //传送json格式的post请求
- export const postRequest = (url, params) => {
- return axios({
- method: 'post',
- url: `${base}${url}`,
- data: params
- })
- }
-
-
- //封装请求
- //传递json的put请求
- export const putRequest = (url, params) => {
- return axios({
- method: 'put',
- url: `${base}${url}`,
- data: params
- })
- }
- //传递json的get请求
- export const getRequest = (url, params) => {
- return axios({
- method: 'get',
- url: `${base}${url}`,
- data: params
- })
- }
- //传递json的delete请求
- export const deleteRequest = (url, params) => {
- return axios({
- method: 'delete',
- url: `${base}${url}`,
- data: params
- })
- }
(7)配置请求转发解决跨域
先获取后端的验证码,请求后端的接口:
在Login.vue里面



访问:图片没有正常显示,

它默认是访问前端的接口 ,前端没有接口,后端的接口是8081,这时候就涉及到跨域:我们8080接口去调8081接口,需要进行跨域:
用了简单的办法:Node.js的代理类去转发,也就是说我们请求还是请求8080,但是请求到Nodejs哪里,Nodejs会给我们转发到8081

新建一个配置:vue.config.js:进行跨域配置:

-
- //新建代理
- let proxyObj = {}
-
- proxyObj['/ws'] = {
- ws: true,
- target: 'ws://localhost:8081'
- };
-
- proxyObj['/'] = {
- //websocket
- ws: false,
- //目标地址
- target: 'http://localhost:8081',
- //发送请求头中host会设置成target
- changeOrigin: true,
- //不重写请求地址
- pathRewrite: {
- '^/': '/'
- }
- }
-
- //默认访问的路径端口
- module.exports = {
- devServer: {
- host: 'localhost',
- port: 8080,
- proxy: proxyObj //代理转发
- }
- }
重启项目,就获取到后端的验证码

(8)登录成功跳转页面
先准备home.vue的组件:用来测试登录成功的

在路由配置中配置home路由:

- import Vue from 'vue'
- import VueRouter from 'vue-router'
- import Login from "@/views/Login";
- import Home from '../views/Home'
-
- Vue.use(VueRouter)
-
- const routes = [
- {
- //加载斜杠,会找到Login
- path: '/',
- name: 'Login',
- component: Login
- },
- {
- path:'/home',
- name:'Home',
- component:Home
- }
-
- ]
-
- const router = new VueRouter({
- routes
- })
-
- export default router
先封装请求拦截器:把token放到请求头里面,上面已经写过这个代码


使用ElementUI的组件:登录的时候动画加载显示:

在Login.vue:el-form中添加:



输入了postRequest之后会自动需要导入:可以把它加入main.js,当在调用的时候用this.postRequest

main.js:
- import Vue from 'vue'
- import App from './App.vue'
- import router from './router'
- //引入elementUI
- import ElementUI from 'element-ui';
- import 'element-ui/lib/theme-chalk/index.css';
-
- import {postRequest} from "./utils/api";
- import {putRequest} from "./utils/api";
- import {getRequest} from "./utils/api";
- import {deleteRequest} from "./utils/api";
-
- Vue.use(ElementUI);
-
- //插件形式使用请求
- Vue.prototype.postRequest=postRequest;
- Vue.prototype.putRequest=putRequest;
- Vue.prototype.getRequest=getRequest;
- Vue.prototype.deleteRequest=deleteRequest;
-
- Vue.config.productionTip = false
-
- new Vue({
- router,
- render: h => h(App)
- }).$mount('#app')
Login.vue组件
-
-
"rules" - v-laoding="loading"
- element-loading-text="正在登录..."
- element-loading-spinner="el-icon-loading"
- element-loading-background="rgba(0,0,0,0.8)"
- ref="loginForm" :model="loginForm" class="loginContainer">
-
"loginTitle">系统登录
-
"username"> -
"text" auto-complete="false" v-model="loginForm.username" placeholder="请输入用户名"> -
-
-
"password"> -
"text" auto-complete="false" v-model="loginForm.password" placeholder="请输入密码"> -
-
-
"code"> -
"text" auto-complete="false" v-model="loginForm.code" placeholder="点击图片更换验证码" style="width:250px;margin-right: 5px"> -
"captchaUrl" @click="updateCaptcha"> -
-
-
"checked" calss="loginRemember">记住我 -
"primary" style="width: 100%" @click="submitLogin">登录 -
-
-
-
-
-
- export default {
- name: "Login",
- //输入框默认显示
- data(){
- return{
- //访问后端接口capcha
- captchaUrl: '/captcha?time=' + new Date(),
- loginForm:{
- username:'admin',
- password:'123',
- code:''
- },
- loading:false,//定义loading
- checked:true,
- //校验规则
- rules:{
- username: [{required:true,message:'请输入名字',trigger:'blur'}],
- password: [{required:true,message:'请输入密码',trigger:'blur'}],
- code: [{required:true,message:'请输入验证码',trigger:'blur'}]
- }
- }
- },
- methods:{
- //点击更新图片
- updateCaptcha(){
- //访问后端接口captcha
- this.captchaUrl='/captcha?time='+new Date();
- },
- submitLogin(){
- //登录校验
- this.$refs.loginForm.validate((valid) => {
- //通过执行
- if (valid) {
-
- this.loading=true;//登录的时候是true
- //api.js封装的post请求,调用后端login接口
- this.postRequest('/login', this.loginForm).then(resp => {
- if (resp) {
- this.loading=false;//登录成功之后loading是false
- //alert(JSON.stringify(resp));
- //存储用户token
- const tokenStr = resp.obj.tokenHead + resp.obj.token;//获取tokenstr
- window.sessionStorage.setItem('tokenStr', tokenStr);//先存放到sessionStorage里面
- /* //清空菜单
- this.$store.commit('initRoutes', []);
- //页面跳转
- let path = this.$route.query.redirect;
- this.$router.replace((path == '/' || path == undefined) ? '/home' : path)*/
- //跳转页面 使用replace 浏览器地址栏不会有往后退的效果
- this.$router.replace('/home')
- }
- })
- } else {
- this.$message.error('请输入所有字段');
- return false;
- }
- })
- }
- }
- }
-
- .loginContainer {
- border-radius: 15px;
- background-clip: padding-box;
- margin: 180px auto;
- width: 350px;
- padding: 15px 35px 15px 35px;
- background: #fff;
- border: 1px solid #eaeaea;
- box-shadow: 0 0 25px #cac6c6;
- }
-
- .loginTitle {
- margin: 0 auto 40px auto;
- text-align: center;
- color: #505458;
- }
-
- /*.loginRemember {
- text-align: left;
- margin: 0px 0px 15px 0px;
- }*/
-
- .el-form-item__content {
- display: flex;
- align-items: center;
- }

点击登录:

(9)导航栏功能实现
创建两个子组件:Test1.vue、Test2.vue
-
- test1
-
-
- export default {
- name: "Test1"
- }
-
-
-
- test2
-
-
- export default {
- name: "Test2"
- }
-
-
更改Home.vue:
这里是通过事件进行跳转:以后会有很多很多的菜单,发现以后会写很多的路由,需要频繁的在路由配置里面去添加,那我们频繁的添加菜单的时候,操作步骤是重复的,所以可以把菜单和路由数据统一起来,将路由数据动态渲染到菜单上去

路由配置:index.js
- import Vue from 'vue'
- import VueRouter from 'vue-router'
- import Login from "@/views/Login"
- import Home from '../views/Home'
- import Test1 from "../views/Test1";
- import Test2 from "../views/Test2";
-
-
- Vue.use(VueRouter)
-
- const routes = [
- {
- //加载斜杠,会找到Login
- path: '/',
- name: 'Login',
- component: Login,
- hidden:true
- },
- {
- path:'/home',
- name:'导航一',
- component:Home,
- children:[
- {
- path:'/test1',
- name:'选项1',
- component:Test1
- },
- {
- path:'/test2',
- name:'选项2',
- component:Test2
- }
- ]
- }
-
-
- ]
-
- const router = new VueRouter({
- routes
- })
-
- export default router
更改Home.vue:
-
-
-
Header -
-
"200px"> -
-
-
-
"1" v-for="(item,index) in this.$router.options.routes" :key="index" v-if="!item.hidden"> - "title">
- "el-icon-location">
- {{item.name}}
-
-
-
"children.path" v-for="(children,index) in item.children">{{children.name}} -
-
-
-
-
"homeRouterView"/> -
-
-
-
-
- export default{
- name:"Home"
- }
-
-
- .homeHeader {
- background-color: #409eff;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0px 15px;
- box-sizing: border-box;
- }
-
- .homeHeader .title {
- font-size: 30px;
- font-family: 华文行楷;
- color: #ffffff;
- }
-
- .homeHeader .userInfo {
- cursor: pointer;
- }
-
- .homeWelcome {
- text-align: center;
- font-size: 30px;
- font-family: 华文行楷;
- color: #409eff;
- padding-top: 50px;
- }
-
- .homeRouterView {
- margin-top: 10px;
- }
-
- .el-dropdown-link img {
- width: 48px;
- height: 48px;
- border-radius: 24px;
- margin-left: 8px;
- }
-
- .el-dropdown-link {
- display: flex;
- align-items: center;
- }
(10)安装Vuex
导航栏已经写好了,可以实现菜单的功能,怎么实现呢?两种办法:
第一种,可以在路由配置中去写,根据有多少菜单,在路由配置中写死就行了,这是比较简单的
第二种:是从后端获取对应的一个菜单数据,然后在我们前端路由这边进行一个相应的转化,为什么从后端获取数据呢?因为这些菜单不能说一直是写死的,就是这些,更能会有变更,变更之后,还要在路由配置中修改,这是比较麻烦的
所以我们选择去后端获取,数据库中存好了,变更之后,数据库也会变,变好之后呢,我们数据是从菜单接口数据获取的,菜单就没必要手动的修改了
通过后端接口获取菜单:

有了这个菜单之后,把菜单存到哪里?
Local Storage Session Storage可以存放我们的菜单,除了这两种,还可以使用Vuex,vuex本质上就是为vue开发的状态管理模式,它采用集中式管理应用的所有组件的状态,并且以相应的规则去保证状态呢以一种可预测的方式发生变化,可以理解为整体的数据的状态管理,只不过它不是存放到浏览器的Session Storage上面,它直接存放在vuex对应的内存里面,Session Storage存储的对用户是可见的


安装vuex:
安装的时候出现问题:


下载完之后:package.json:多了vuex

创建目录:store,创建配置index.js

这里只是简单的写了下配置,以后还会继续写
- import Vue from 'vue'
- import Vuex from 'vuex'
-
- Vue.use(Vuex)
-
- export default new Vuex.Store({
- //state可以理解为全局的对象,用来保存组件的公共数据
- state:{
- routes:[]
- },
-
- //mutations:表示可以改变state里面的对应值的一个对应方法(同步执行的)异步执行的是actions方法
- mutations:{
- //初始化路由
- initRoutes(state,data){
- state.routes=data;
- }
- }
- })
在main.js引入vuex的配置

加一个store:

(11)封装菜单请求工具类
要获取到后端的菜单数据,后端的是一个字符串,需要把它转换为前端所需要的一个对象,并且把这个数据放到路由的配置里面去,我们需要封装一个菜单请求工具类去实现我们的要求
创建menus.js:

- import {getRequest} from "./api";
-
- export const initMenu = (router, store) => {
- //先判断store中的state是否为空
- if (store.state.routes.length > 0) {
- return;
- }
- //get请求调用接口/system/cfg/menu:,初始化 data:拿到的数据
- getRequest("/system/cfg/menu").then(data => {
- //判断data是否存在
- if (data) {
- //格式化router
- let fmtRoutes = formatRoutes(data);
- //添加到router
- router.addRoutes(fmtRoutes);
- //将数据存入vuex
- store.commit('initRoutes', fmtRoutes);
-
- }
- })
- }
-
- //格式化数据方法
- export const formatRoutes = (routes) => {
- let fmRoutes = [];
- routes.forEach(router => {
- let {
- path,
- component,
- name,
- meta,
- iconCls,
- children,
- } = router;
- if (children && children instanceof Array) {
- //递归
- children = formatRoutes(children);
- }
- //格式化
- let fmRouter = {
- path: path,
- name: name,
- meta: meta,
- iconCls: iconCls,
- children: children,
- component(resolve) {
- require(['../views/' + component + '.vue'], resolve);
-
- }
- }
- fmRoutes.push(fmRouter);
- })
- return fmRoutes;
- }
(12)完善菜单请求工具类


创建组件:一 一的创建出来,以EmpAdv为例:其他的不写了
-
- 高级资料
-
-
- export default {
- name: "EmpAdv"
- }
-
-
修改菜单配置menu.js:

- import {getRequest} from "./api";
- //初始化方法
- export const initMenu = (router, store) => {
- //先判断store中的state是否为空
- if (store.state.routes.length > 0) {
- return;
- }
- //get请求调用接口/system/cfg/menu:,初始化 data:拿到的数据
- getRequest("/system/cfg/menu").then(data => {
- //判断data是否存在
- if (data) {
- //格式化router
- let fmtRoutes = formatRoutes(data);
- //添加到router
- router.addRoutes(fmtRoutes);
- //将数据存入vuex
- store.commit('initRoutes', fmtRoutes);
- //连接websocket
- //store.dispatch('connect');
- }
- })
- }
-
- //格式化数据方法
- export const formatRoutes = (routes) => {
- let fmRoutes = [];
- routes.forEach(router => {
- let {
- path,
- component,
- name,
- meta,
- iconCls,
- children,
- } = router;
- if (children && children instanceof Array) {
- //递归
- children = formatRoutes(children);
- }
- //格式化
- let fmRouter = {
- path: path,
- name: name,
- meta: meta,
- iconCls: iconCls,
- children: children,
- component(resolve) {
- if (component.startsWith("Home")) {
- require(['../views/' + component + '.vue'], resolve);
- } else if (component.startsWith("Emp")) {
- require(['../views/emp/' + component + '.vue'], resolve);
- } else if (component.startsWith("Per")) {
- require(['../views/per/' + component + '.vue'], resolve);
- } else if (component.startsWith("Sal")) {
- require(['../views/sal/' + component + '.vue'], resolve);
- } else if (component.startsWith("Sta")) {
- require(['../views/sta/' + component + '.vue'], resolve);
- } else if (component.startsWith("Sys")) {
- require(['../views/sys/' + component + '.vue'], resolve);
- }
- }
- }
- fmRoutes.push(fmRouter);
- })
- return fmRoutes;
- }
(13)路由导航守卫介绍
现在把菜单请求工具类写完了,就是在什么时候调用initMenu初始化方法,去初始化菜单,毫无疑问,就是在登录的时候,但是需要考虑,现在是把菜单放在vuex里面的,也就类似内存里面,而且现在是浏览器的运用,如果用户按下了刷新按钮,就会可能被初始化数据(空数据)刷新,菜单就可能丢失,怎么解决丢失呢?
比如说在Home.vue按了F5刷新,那我页面Home添加上初始化,菜单就行了呀!这样处理也可以,但是需要考虑用户不只是在Home页,按F5刷新,比如说在高级资料EmpAdv去刷新,那么之前放在Home页的初始化菜单,它也没有办法去调,也就不会生效,还会出现菜单丢失的情况,那怎么解决,只能在每个页面添加初始化菜单的方法,这样是非常麻烦的,那我们还有非常简单的东西叫:“路由导航守卫”



to:是跳转到那个路由
from:是从那个路由跳转的
next():如果没有next() 是不能实现跳转的
(14)菜单功能完整实现
main.js:
- import Vue from 'vue'
- import App from './App.vue'
- import router from './router'
- //引入vuex
- import store from "./store";
- //引入elementUI
- import ElementUI from 'element-ui';
- import 'element-ui/lib/theme-chalk/index.css';
-
- import {postRequest} from "./utils/api";
- import {putRequest} from "./utils/api";
- import {getRequest} from "./utils/api";
- import {deleteRequest} from "./utils/api";
- import {initMenu} from "./utils/menus";
-
- Vue.use(ElementUI);
-
- //插件形式使用请求
- Vue.prototype.postRequest=postRequest;
- Vue.prototype.putRequest=putRequest;
- Vue.prototype.getRequest=getRequest;
- Vue.prototype.deleteRequest=deleteRequest;
-
- Vue.config.productionTip = false
-
- //路由导航守卫
- router.beforeEach((to,from,next)=>{
- ///登录的时候把token放在了sessionStorage里面,可以去判断是否有这个token
- if (window.sessionStorage.getItem('tokenStr')) {
- //初始化菜单
- initMenu(router, store);
- next();
- }else{
- next();
- }
-
- })
-
-
- new Vue({
- router,
- store,
- render: h => h(App)
- }).$mount('#app')
更改Home.vue:


-
-
-
Header -
-
"200px"> -
-
-
-
"index+''" v-for="(item,index) in routes" :key="index" v-if="!item.hidden"> - "title">
- "el-icon-location">
- {{item.name}}
-
-
-
"children.path" v-for="(children,index) in item.children">{{children.name}} -
-
-
-
-
"homeRouterView"/> -
-
-
-
-
- export default{
- name:"Home",
- //计算属性
- computed: {
- routes() {
- return this.$store.state.routes;
- }
- }
- }
-
-
-

更换一下图标:图标是font-awesome的图标需要安装:


在main.js:导入css

然后更改Home.vue:


(15)获取用户信息功能实现
先设置一下标题:
Home.vue:

设置样式:

添加头像:
首先在main.js中添加:

在Home.vue中首先获取到用户信息,就可以进行相关的操作了:

添加:表头信息:

-
-
-
"homeHeader"> - "title">云E办
-
-
"userInfo"> - "el-dropdown-link">
- {{user.name}}
-
"user.userFace"> -
-
"dropdown"> -
个人中心 -
设置中心 -
注销 -
-
-
-
-
"200px"> -
-
-
-
"index+''" v-for="(item,index) in routes" :key="index" v-if="!item.hidden"> - "title">
- "item.iconCls" style="color: #1accff;margin-right: 5px">
- {{item.name}}
-
-
-
"children.path" v-for="(children,index) in item.children" :key="index"> - {{children.name}}
-
-
-
-
-
-
"homeRouterView"/> -
-
-
-
-
- export default{
- name:"Home",
- data() {
- return {
- //拿到用户对象
- user: JSON.parse(window.sessionStorage.getItem("user"))
- }
- },
- //计算属性
- computed: {
- routes() {
- return this.$store.state.routes;
- }
- }
- }
-
-
- .homeHeader {
- background-color: #409eff;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 0px 15px;
- box-sizing: border-box;
- }
-
- .homeHeader .title {
- font-size: 30px;
- font-family: 华文行楷;
- color: #ffffff;
- }
-
- .homeHeader .userInfo {
- cursor: pointer;
- }
-
- .homeWelcome {
- text-align: center;
- font-size: 30px;
- font-family: 华文行楷;
- color: #409eff;
- padding-top: 50px;
- }
-
- .homeRouterView {
- margin-top: 10px;
- }
-
- .el-dropdown-link img {
- width: 48px;
- height: 48px;
- border-radius: 24px;
- margin-left: 8px;
- }
-
- .el-dropdown-link {
- display: flex;
- align-items: center;
- }
