云E办项目练手

前端的创建

一. 前端项目创建

  1. 首先一般情况下,会先执行这个代码
    npm uninstall -g vue-cli
    npm install -g @vue/cli

  2. 然后再执行(这个是:防止系统禁止运行脚本)
    set-ExecutionPolicy Remotesigned

  3. 开始创建项目
    vue create yeb

  4. 然后选择下面
    在这里插入图片描述

  5. 然后也是上下移动,空格选择
    在这里插入图片描述

  6. 然后就是第一个N ,其他的y或者n都可以,随便。

  7. 然后就是可以cd hello 了 并且npm run serve了

  8. 大概样子就是这个样子啦
    在这里插入图片描述

     (1)这个就是平时开发的vue-cli项目的结构了
     node-modules:用于存放项目的依赖文件
     public:公共目录
     src:项目源码目录
     .gitignore:git忽略的配置文件
     babel.config.js:Babel配置文件,主要作用是将Es6转为Es5(因为平时需要都是用Es5规范)
     package.json:项目的配置文件
     	name:项目名称
     	version:项目版本
     	description:项目描述
     	author:项目作者
     	scripts:封装常用命令
     	还有就是我们下载的一些内容了
     	ependencies:生产环境依赖
     	devDependencies:开发环境依赖
     (2)public目录
     		favicon.ico是网页图标
     		index.html首页,仅作为魔板页,实际开发是不用的
     (3)src就灭必要细讲了,如果你没有学习过VUe,请移步到我的列表里面有Vue笔记
     (4)main.js
    
mport Vue from 'vue' :ES6 写法,会被转换成 require("vue"); (require 是 NodeJS 提
供的模块加载器)
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

import App from './App.vue' :意思同上,但是指定了查找路径, ./ 为当前目录
Vue.config.productionTip = false :关闭浏览器控制台关于环境的相关提示
new Vue({...}) :实例化 Vue
router :使用router组件
render: h => h(App) :ES6写法,渲染App组件
.$mount('#app') :手动挂载,与之前的 el:'#app' 作用
(5)具体还有其他的我就不细讲了,如果没有学过Vue,建议你去大概的学习一下

二.创建好啦项目之后的配置

(一). 登录页面

–1.(主页面)

1.1 安装需要用来展示的页面的:ElementUi

执行如下命令就可以了
npm i element-ui -s
-s的意思是:将模块安装到项目目录下,并在 package 文件的 dependencies 节点写入依赖

1.2 导入Element-UI

在main.js文件做出如下修改:
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)

在这里插入图片描述
气人哦,那个index.css写成为了index报错名字写错了。

1.3 编写我们的Login.vue(登录组件)

<template>
    <div>
        <h4>Login</h4>
    </div>
</template>

<script>
    export default {
        name: "Login"
    }
</script>

<style scoped>
</style>



然后再编写我们的路由:反正就是每次编写一个组件,然后就要在index.js文件里面编写我们的路由


import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '../views/Login.vue'

Vue.use(Router)

export default new Router({
    routes: [{
            path: '/',
            name: 'Login',
            component: Login
        },
        {
            path: '/helloworld',
            name: 'HelloWorld',
            component: HelloWorld
        }
    ]
})

到这里我们就大概的理解怎么编写一个组件了,接下里我们开始详细的登录页面编写

1.4 具体代码

//这下面到时候抽出来展示的页面
<template>
    <div>
        <el-form :rules="rules" :model="loginForm" class="loginContainer">
            <h3 class="loginTitle">系统登录</h3>
            <el-form-item prop="username">
                <el-input type="text" v-model="loginForm.username" auto-complete="false"
                          placeholder="请输入用户名"></el-input>
            </el-form-item>
            <el-form-item prop="password">

                <el-input type="password" v-model="loginForm.password" auto-complete="false"
                          placeholder="请输入密码"></el-input>
            </el-form-item>
            <el-form-item prop="code">
                <el-input size="normal" type="text" v-model="loginForm.code" auto-complete="false"
                          placeholder="点击图片更换验证码" style="width: 250px;margin-right: 5px"></el-input>
                <img :src="captchaUrl">
            </el-form-item>
            <el-checkbox class="loginRemember" v-model="checked">记住我</el-checkbox>
            <el-button type="primary" style="width: 100%">登录</el-button>
        </el-form>
    </div>
</template>

       

//这里是定义的JavaScript的代码,也就是行为的代码
<script>
    export default {
        name: "Login",
        data() {
            return {
                captchaUrl: '',
                loginForm: {
                    username: 'admin',
                    password: '123',
                    code:''
               },
                checked: true,
                rules: {
                    username: [{required: true, message: '请输入用户名', trigger: 'blur'}],
                    password: [{required: true, message: '请输入密码', trigger: 'blur'}],
                    code: [{required: true, message: '请输入验证码', trigger: 'blur'}]
               }
           }
        }
    }
</script>

//这里是Css的代码,到时候也是会抽出来的,这里我们就是不用改变的
<style>
    .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: 0px auto 40px auto;
        text-align: center;
        color: #505458;
        
    }
    .loginRemeber {
        text-align: left;
        margin:0px 0px 15px 0px
    }
    .el-from-item__content {
        display: flex;
        align-items: center;
    }
</style>

1.5 编写登录的事件

<template>
    <div>
        <el-form :rules="rules" :model="loginForm" class="loginContainer">
            <h3 class="loginTitle">系统登录</h3>
            <el-form-item prop="username">
                <el-input type="text" v-model="loginForm.username" auto-complete="false"
                          placeholder="请输入用户名"></el-input>
            </el-form-item>
            <el-form-item prop="password">

                <el-input type="password" v-model="loginForm.password" auto-complete="false"
                          placeholder="请输入密码"></el-input>
            </el-form-item>
            <el-form-item prop="code">
                <el-input size="normal" type="text" v-model="loginForm.code" auto-complete="false"
                          placeholder="点击图片更换验证码" style="width: 250px;margin-right: 5px"></el-input>
                <img :src="captchaUrl">
            </el-form-item>
            <el-checkbox class="loginRemember" v-model="checked">记住我</el-checkbox>
            <el-button type="primary" style="width: 100%" @click="submitLogin">登录</el-button>
        </el-form>
    </div>
</template>

       

<script>
    export default {
        name: "Login",
        data() {
            return {
                captchaUrl: '',
                loginForm: {
                    username: 'admin',
                    password: '123',
                    code:''
               },
                checked: true,
                rules: {
                    username: [{required: true, message: '请输入用户名', trigger: 'blur'}],
                    password: [{required: true, message: '请输入密码', trigger: 'blur'}],
                    code: [{required: true, message: '请输入验证码', trigger: 'blur'}]
               }
           }
        },
        methods: {
            submitLogin() {
                this.$refs.loginForm.validate((valid)=>{
                    if(valid) {
                        alert('aaa')
                    } else {
                        this.$message.console.error('请输入所有字段');
                        return false;
                    }
                })
            }
        }
    }
</script>

<style>
    .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: 0px auto 40px auto;
        text-align: center;
        color: #505458;
        
    }
    .loginRemeber {
        text-align: left;
        margin:0px 0px 15px 0px
    }
    .el-from-item__content {
        display: flex;
        align-items: center;
    }
</style>

注意看的是在登录上面的标签上面的那个事件,然后就是methods里面的方法,在if判断之后再里面进行逻辑实现,比如下面是微人事项目的逻辑实现
在这里插入图片描述

–2. Axios的应用

首先我们来看一下为什么要Axios:首先我们的页面是编写好了,但是我们的前端请求咱们到后端呢?所有懂了吧,咱们的Vue正是用了Axios来解决的这种通信问题,大家可以把它简单的理解为Ajax

1.1 首先我们要安装Axios

npm install axios
在这里插入图片描述

1.2 封装请求

每一次网络请求都有可能成功或者失败。成功有成功的处理方式,失败一般都是提示错误信息。我们希望将所有的失败统一进行处理提示错误信息而不是每失败一次处理一次,因此我们将网络请求进行封装,达到统一处理失败信息的目的。
这里要注意的是在utils目录下新建api.js文件

  1. api.js文件里面编写如下
import axios from 'axios'
import {Message} from 'element-ui';
import router from '../router'
//响应拦截器
axios.interceptors.response.use(success => {
    //业务逻辑错误
    if (success.status && success.status == 200) {
        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 => {
    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 = '';
//传送json格式的post请求,主要写代码都在这里
export const postRequest = (url, params) => {
    return axios({
        method: 'post',
        url: `${base}${url}`,
        data: params
   })
}

一般都是通过export 这样编写方法来暴露,进行编写:比如下面的是微人事的项目的
在这里插入图片描述

1.3 配置请求转发解决跨域

新建vue.config.js,并且编写代码如下:

let proxyObj = {}
proxyObj['/'] = {
    //websocket
    ws: false,
    //目标地址
    target: 'http://localhost:8081',
    //发送请求头中host会设置成target
    changeOrigin: true,

    //不重写请求地址
    pathRewrite: {
        '^/': '/'
    }
}
module.exports = {
    devServer: {
        host: 'localhost',
        port: 8080,
        proxy: proxyObj
    }
}

1.4 验证码的配置

  1. 文件的修改
    验证码后端直接返回图片,直接通过 img 标签的src属性即可获取。添加图片的点击事件,请求时 time参数是为了确保验证码能够正确刷新
    在Login.vue文件中把关于验证码的那个el-from-item>标签换成为:
</el-form-item>
             <el-form-item prop="code">
                <el-input size="normal" type="text" v-model="loginForm.code" auto-complete="false"
                          placeholder="点击图片更换验证码" style="width:  250px;margin-right: 5px"></el-input>
                <img :src="captchaUrl" @click="updateCaptcha">
</el-form-item>
  1. 咱们再来修改我们的登录的事件,也就是script标签里面的内容
<script>
    import {postRequest} from "../utils/api";
    export default {
        name: "Login",
        data() {
            return {
                captchaUrl: '/captcha?time=' + new Date(),
                loginForm: {
                    username: 'admin',
                    password: '123',
                    code:''
               },
                checked: true,
                rules: {
                    username: [{required: true, message: '请输入用户名', trigger: 'blur'}],
                    password: [{required: true, message: '请输入密码', trigger: 'blur'}],
                    code: [{required: true, message: '请输入验证码', trigger: 'blur'}]
               }
           }
        },
        methods: {
            updateCaptcha() {
                this.captchaUrl='/captcha?time=' + new Date();
            },
            submitLogin() {
                this.$refs.loginForm.validate((valid)=>{
                    if(valid) {
                        //接下来就是开始编写登录的业务逻辑的实现了,就是要用到我们刚才在api.js文件里面编写的方法
                        postRequest('/login', this.loginForm.then(resp =>{
                            if(resp) {
                                alert(JSON.stringify(resp));
                            }
                        }))
                        alert('aaa')
                    } else {
                        this.$message.console.error('请输入所有字段');
                        return false;
                    }
                })
            }
        }
    }
</script>

具体的做法可能第一次做项目的人不是很理解,这里画图解释一下:
在这里插入图片描述
我这里就不能来展示效果了,因为我先编写的前端代码
在这里插入图片描述

(二)登录进去之后的跳转

–1. 主页面编写

2.1 编写home页面

 在views目录新建一个home.vue文件
<template>
    <div>
       Home
    </div>
</template>
<script>
    export default {
        name: "Home"
   }
</script>
<style scoped>
</style>

然后第一件事情就是编写路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '../views/Login.vue'
import Home from '../views/Home'

Vue.use(Router)

export default new Router({
    routes: [{
            path: '/',
            name: 'Login',
            component: Login
        },
        {
            path: '/home',
            name: 'Home',
            component: Home
        },
        {
            path: '/helloworld',
            name: 'HelloWorld',
            component: HelloWorld
        }
    ]
})

2.2 登录的事件逻辑再编写

submitLogin() {
                this.$refs.loginForm.validate((valid)=>{
                    if(valid) {
                        this.loading = true;
                        //接下来就是开始编写登录的业务逻辑的实现了,就是要用到我们刚才在api.js文件里面编写的方法
                        postRequest('/login', this.loginForm.then(resp =>{
                            if(resp) {
                                this.$router.replace('/home');
                            }
                        }))
                        alert('aaa')
                    } else {
                        this.$message.console.error('请输入所有字段');
                        return false;
                    }
                })
            }

在这里插入图片描述

ush :添加页面,可以通过浏览器的后退按钮回到之前页面
replace :替换页面,不可以通过浏览器的后退按钮回到之前页面
element-loading-text :加载文案,显示在加载图标的下方
element-loading-spinner :加载图标类名
element-loading-background :加载背景色值

–2. 来完善一下api.js

后端的登录接口是返回一个token,我们除了登录接口外每一次请求都要在请求头里携带这个token方便后端校验,因此我们需要对请求进行拦截。

2.1 api.js文件内容的编写

import axios from 'axios'
import {Message} from 'element-ui';
import router from '../router'


//请求拦截器
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 => {
    //业务逻辑错误
    if (success.status && success.status == 200) {
        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 => {
    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 = '';
//传送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}',
        date: 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
   })
}

2.2 咱们再把我们编写的这些方法组件化,以后就能在想要用的地方,直接写这个方法就可以了

//导入Element-Ui
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

//显示的使用Element-Ui
Vue.use(ElementUI)

Vue.config.productionTip = false

import {postRequest} from "./utils/api";
import {getRequest} from "./utils/api";
import {putRequest} from "./utils/api";
import {deleteRequest} from "./utils/api";

//插件
Vue.prototype.postRequest = postRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.prototype.getRequest = getRequest;

new Vue({
    router,
    render: h => h(App)
}).$mount('#app')

2.3 在Login.vue里面用我们编写的方法试一下

submitLogin() {
                this.$refs.loginForm.validate((valid)=>{
                    if(valid) {
                        this.loading = true;
                        //接下来就是开始编写登录的业务逻辑的实现了,就是要用到我们刚才在api.js文件里面编写的方法
                        postRequest('/login', this.loginForm.then(resp =>{
                            if(resp) {
                                //存储用户的token信息‘
                                const tokenStr = resp.obj.tokenHead+resp.obj.token;
                                window.sessionStorage.setItem('tokenStr',tokenStr);
                                this.$router.replace('/home');
                            }
                        }))
                    } else {
                        this.$message.console.error('请输入所有字段');
                        return false;
                    }
                })
            }

(三)首页的实现

–1首页页面(home.vue文件)

3.1 需要准备的两个测试文件test1.vue和test2.vue

<template>
    <div>
       Test1
    </div>
</template>
<script>
    export default {
        name: "Test1"
   }
</script>
<style scoped>
</style>



<template>
    <div>
       Test1
    </div>
</template>
<script>
    export default {
        name: "Test1"
   }
</script>
<style scoped>
</style>


以前说过的,编写了每一个组件,那么我们就必须记得要去配置路由
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Login from '../views/Login.vue'
import Home from '../views/Home'
import Test1 from '../views//Test1'
import Test2 from '../views//Test2'

Vue.use(Router)

export default new Router({
    routes: [{
            path: '/',
            name: 'Login',
            component: Login
        },
        {
            path: '/home',
            name: 'Home',
            component: Home,
            children: [
                {
                    path: '/test1',
                    name: 'Test1',
                    component: Test1
                },
                {
                    path: '/test2',
                    name: 'Test2',
                    component: Test2
                },
            ]
        },
        {
            path: '/helloworld',
            name: 'HelloWorld',
            component: HelloWorld
        }
    ]
})

3.2 咱们就来编写Home.vue

<template>
    <div>
        <el-container>
            <el-header class="homeHeader">
                <div class="title">云E办系统</div>
            </el-header>
            <el-container>
                <el-aside width="200px">
                    <el-menu @select="menuClick">
                        <el-submenu index="1">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>导航一</span>
                            </template>
                            <el-menu-item index="/test1">选项1</el-menu-item>
                            <el-menu-item index="/test2">选项2</el-menu-item>
                        </el-submenu>
                    </el-menu>
                </el-aside>
                <el-main>
                    <router-view/>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>
<script>
    export default {
        name: "Home",
        methods: {
            menuClick(index) {
                this.$router.push(index);
            }
        }
   }
</script>
<style scoped>
</style>

来分析一下我们的内容
在这里插入图片描述

select :菜单激活回调
index :选中菜单项的 index
index Path :选中菜单项以及所属父菜单项的index数组

在这里插入图片描述

3. 3渲染路由数据

他本人说的:我们需要频繁添加菜单选项的时候会发现操作的步骤比较重复,因此我们可以将菜单和路由数据统一起来,将路由数据动态渲染到菜单上
我自己的理解来:给自己找一个问题:
康康下面的代码中,是不是感觉我们每当要增加一个新的导航栏的时候,我们都要在这里去添加:怎么解决呢?
在这里插入图片描述
怎么把它给抽出来,这样岂不是不用那么麻烦的去写了(【但是我感觉更麻烦吧,咱们先这样理解吧】)
在这里插入图片描述

(四)获取菜单接口数据

这里需要对我们为什么这样写有个大致的了解再进行下面的学习。

4.0 大致了解为什么要学习下面的内容

在这里插入图片描述

导航栏是这个样子的,下面有测试一和测试二对吧!
上面的是我们在路由里面写死的,不够灵活。

在这里插入图片描述

再来看看我们前端的展示的写法,下面这样的写法,我们可以把要展示的都放到数据库
里面,不管你有多少,我们都在去数据库里面找,然后进行展示,所以有了我们接下来要学习的内容了
<el-menu router unique-opened>
                        <el-submenu :index="index + ''" v-for="(item,index) in this.$router.options.routes" :key="index" :if="!item.hidden">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>{{item.name}}</span>
                            </template>
                            <el-menu-item :index="children.path" v-for="(children,indexj) in item.children" :key="indexj">
                                {{children.name}}
                            </el-menu-item>
                        </el-submenu>
</el-menu>

Vuex 是一个专为 Vue.js 应用程序开发的 状态管理模式。它采用集中式存储管理应用的所有组件的状
态,并以相应的规则保证状态以一种可预测的方式发生变化。{我问了我的老师,他给我说的让我直接简单点理解,就是相当于缓存}

----1. Vuex的使用

  1. 安装Vuex
    npm install vuex --save
  2. 配置Vuex
    在src目录下创建一个store的目录用来配置store,然后再到里面创建index.js的文件
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
    state: {
        routes: []
   },
    mutations: {
        initRoutes(state, data) {
            state.routes = data;
       }
   },
    actions: {}
})

state :全局state对象,用于保存所有组件的公共数据
getters :监听state值的最新状态(计算属性)
mutations :唯一可以改变state值的方法(同步执行)
actions :异步执行mutations方法
  1. 咱们编写了配置,那肯定都要在main.js文件里面配置:

     配置如下:
     	import store from './store'
    
     	new Vue({
         	router,
     		store,
     		render: h => h(App)
     	}).$mount('#app')
    
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

//导入Element-Ui
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

//显示的使用Element-Ui
Vue.use(ElementUI)

Vue.config.productionTip = false

import { postRequest } from "./utils/api";
import { getRequest } from "./utils/api";
import { putRequest } from "./utils/api";
import { deleteRequest } from "./utils/api";

//插件
Vue.prototype.postRequest = postRequest;
Vue.prototype.putRequest = putRequest;
Vue.prototype.deleteRequest = deleteRequest;
Vue.prototype.getRequest = getRequest;

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app')

4.1配置好啦,就来编写代码

  1. 封装菜单请求工具类

    后端接口返回的数据中component的值为String,我们需要将其转换为前端所需的对象并且我们需要将数据放到路由的配置里面,,所有我们需要封装菜单请求工具类实现我们的需求。

  2. 在utils下面创建menus.js文件

//下面这句话,不用说了吧,咱们昨天自己编写的方法哦
import {getRequest} from "./api";



export const initMenu = (router, store) => {
    if (store.state.routes.length > 0) {
        return;
   }
    getRequest("/system/config/menu").then(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;
}

反正暂时上面的我是看不懂

4.2我们来编写需要的页面的组件

创建好就是这样的
在这里插入图片描述
4.3 完成我们的menus.js

//下面这句话,不用说了吧,咱们昨天自己编写的方法哦
import {getRequest} from "./api";



export const initMenu = (router, store) => {
    //就是如果数据已经存在了,就直接返回
    //这里调用的是,store目录下面的index.js来判断的
    if (store.state.routes.length > 0) {
        return;
   }
    getRequest("/system/config/menu").then(data => {
        if (data) {
            //格式化router
            let fmtRoutes = formatRoutes(data);
            //添加到router
            router.addRoutes(fmtRoutes);
            //将数据存入vuex,这个方法是在store里面的
            store.commit('initRoutes',fmtRoutes);
       }
   })
}

//传进来的是data,这里的Data就是路由了
export const formatRoutes = (routes) => {
    let fmRoutes = [];
    routes.forEach(router => {
        let {
            path,
            //这个component代表了路劲,Emp。per等
            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不是一个简单的component,是一个组件的嘞
            component(resolve) {
                if (component.startswith("Emp")) {
                    require(['../views/' + component + '.vue'], resolve);
                } else if (component.startswith("Per")) {
                    require(['../views/' + component + '.vue'],resolve);
                }else if (component.startswith("Sal")) {
                    require(['../views/' + component + '.vue'],resolve);
                }else if (component.startswith("Sta")) {
                    require(['../views/' + component + '.vue'],resolve);
                }else if (component.startswith("Sys")) {
                    require(['../views/' + component + '.vue'],resolve);
                }
                
           }
       }
       //放到路由里面
        fmRoutes.push(fmRouter);
   })
    return fmRoutes;
}


----2. 到这里就作为中场休息一下吧----------

前面时间是八月二十九对所有课程暂时放着的,忙着开学准备,接下来的时间(九月四号开学对接下来的内容认证学习)

4.3 对前面的大致总结和复习

上次我们大概做成了这个样子
在这里插入图片描述
然后就是我们当点击了这个选项一或者选项二的时候,给我们展示不同的数据,然后就编写了这个menus.js的类来作为数据的展示和vuex来作为缓存。
上面我们已经编写了这个menus.js的文件,接下来我们要来看一下导航守卫了

4.4 导航守卫

  1. 问题介绍
    菜单数据在用户点击刷新按钮时可能出现丢失的情况。
    【这个是一种什么样子的情况呢?
    我们的菜单:menus.js文件
    那么要在什么时候才调用进行初始化菜单呢(也就是初始化我们的initMenu),
    1)大概意思就是:我们肯定都是会去想,毫无疑问就是在登录的时候去 初始化菜单,但是不要忘记了这个我们的菜单是放到了Vuex里面的呀(相当于放到了内存里面的了),这是用户按了刷新按钮可能就是会数据丢失的情况哦。
export default new Vuex.Store({
    state: {
        routes: []
    },
    mutations: {
        initRoutes(state, data) {
            state.routes = data;
        }
    },
    actions: {}
})

  1. 解决办法
    1)在每一个页面添加初始化菜单的方法,这显然很麻烦
    2)第二种就是我们的导航守卫,而且我们的vue-router提供的导航守卫主要用来通过跳转或取消的方式守卫导航。有多重机会植入路由导航过程中:全局的,单个路由独享的,或者组件级的。

记住参数或查询的改变并不会触发进入/离开的导航守卫。我们可以观察通过$router对象应对这些变化,或使用beforeRouteUpdate的组件内守卫。

  1. 使用beforeRouteUpdate注册一个前置守卫。
//我们在这里使用导航栏守卫
router.beforeEach( (to,from,next) => {
    //....
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫resolve完之前一直处于等待中。
每一个守卫方法接受三个参数:
1)to: Route,即将要进入的目标,路由对象。
2)from:Route,当前导航正要离开的路由。
3)next:可以传入false或者true都可以,false表示终止跳转,true表示可以通过

Function,一定要调用该方法来resolve这个钩子,如果全部钩子执行完毕,则导航的状态就是confirmed(确认的)。
next(false)中断当前的导航。如果浏览器的URL改变了(可能就是用户手动或者浏览器后退按钮),那么URL地址会重置到from路由对应的地址。
next(‘/’)或者next({path:'/'})跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以像next传递任意对象,且运行设置诸如replace:true,name:‘home’之类的选项以及任何用在router-link的to prop或router.push中的选项。
next(error) : (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。

确保要调用 next 方法,否则钩子就不会被 resolved。

  1. 接下来看看这个到底怎么编写嘛
router.beforeEach( (to,from,next) => {
    // initMenu(router,store);
    // next();

	//如果没有登录的话,那就不用初始化菜单
    if (to.path=='/') {
        next();
    } else {
        initMenu(router,store);
        next();
    }
})
  1. 咱们再来看看这个Home.vue文件
<template>
    <div>
        <el-container>
            <el-header class="homeHeader">
                <div class="title">云E办系统</div>
            </el-header>
            <el-container>
                <el-aside width="200px">
                    <!-- <el-menu @select="menuClick">
                        <el-submenu index="1">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>导航一</span>
                            </template>
                            <el-menu-item index="/test1">选项1</el-menu-item>
                            <el-menu-item index="/test2">选项2</el-menu-item>

                        </el-submenu>
                    </el-menu> -->

                    <el-menu router unique-opened>
                        <el-submenu :index="index + ''" v-for="(item,index) in this.$router.options.routes" :v-if="!item.hidden" :key="index">
                            <template slot="title">
                                <i class="el-icon-location"></i>
                                <span>{{item.name}}</span>
                            </template>
                            <el-menu-item :index="children.path" v-for="(children,indexj) in item.children" :key="indexj">
                                {{children.name}}
                            </el-menu-item>
                        </el-submenu>
                    </el-menu>
                </el-aside>
                <el-main>
                    <router-view/>
                </el-main>
            </el-container>
        </el-container>
    </div>
</template>
<script>
    export default {
        name: "Home",
        computed: {
            routes() {
                return this.$store.routes;
            }
        }
   }
</script>
<style scoped>
</style>

4.5图标的使用

  1. 这个就是我们平时开发的那些按钮上面显示不同的效果,然后展示给用户,要搞上好看的图标撒
  2. 下载
    1)npm install font-awesome --save
    2)在main.js里面导入进来这个样式:import ‘font-awesome/css/font-awesome.min.css’;
    3)然后就是使用了 <i style="color: #1accff;margin-right: 5px" :class="item.iconCls"></i>,这句话,因为我之前还没有开发后台的东西,所有这里登录后会报未知错误的,基本不会变的。
<el-menu router unique-opened>
                        <el-submenu :index="index + ''" v-for="(item,index) in routes" :key="index" :if="!item.hidden">
                            <template slot="title">
                                <i class="item.iconCls"></i>
                                <span>{{item.name}}</span>
                            </template>
                            <el-menu-item :index="children.path" v-for="(children,indexj) in item.children" :key="indexj">
                                {{children.name}}
                            </el-menu-item>
                        </el-submenu>
                    </el-menu>
  1. 大概这样测试一下
    在这里插入图片描述

    这里对menus.js文件修改一下

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);
                    }

                }

版权声明:本文为weixin_46635575原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。