1、登录退出功能
1.1、登录业务流程
- 登录页输入用户名和密码
- 调用后台接口进行验证
- 通过验证后,根据后台的响应状态跳转到项目主页
技术点
- http是无状态的
- 通过cookie在客户端记录状态,通过session在服务端记录状态(没有跨域问题)
- 通过token方式维持状态(有跨域问题)
token原理
1.2、登录功能实现
命令行创建login新分支并切换到login分支
git checkout -b login
查看所有分支
git branch
- 创建项目后清除默认页面。默认路由
- 创建login组件,配置login的路由规则,并把根路径重定向到login路径
- element组件按需引入,在plugins文件夹下的element.js里面引入
- elementui可以通过
prefix-icon
和suffix-icon
属性在 input 组件首部和尾部增加显示图标,也可以通过 slot 来放置图标。 - 引入iconfont
- 表单的数据绑定,给表单绑定loginForm对象,两个输入框分别绑定对象里的属性。
- 表单数据的校验,elementui里Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可。校验规则参见 async-validator
- rules:requied必填项,message出错提醒,trigger触发事件等等
- 在数据里定义验证对象,然后给表单 rules 属性传入约定,给表单项prop 属性设置为需校验的字段名就可以
- 表单的重置,element里的resetFields方法对整个表单进行重置,将所有字段值重置为初始值并移除校验结果
- 给表单设置ref=“loginFormRef”使得后面能够拿到表单元素,给按钮绑定重置方法
- 当我们点击登录的时候,不是就直接发送网络请求了,需要进行登录前的预验证,当我们点击登录的时候,不是就直接发送网络请求了,需要进行登录前的预验证,如果数据检验都通过了,valid为true,如果有不通过,则返回false。
- 根据预验证决定是否发起请求,先配置axios,按下面那样,可以在每一个组件上通过
this.$http
获取axios,不必每个页面都import axios,$http
是自定义的属性
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import './plugins/element.js'
// 导入全局样式
import '@/assets/css/global.css'
// 导入字体图标
import '@/assets/fonts/iconfont.css'
// 导入axios
import axios from 'axios'
// 配置请求的根路径
axios.defaults.baseURL='http://127.0.0.1:8888/api/private/v1/'
Vue.config.productionTip = false
Vue.prototype.$http=axios
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
login()
{
this.$refs.loginFormRefs.validate(async valid=>{
// console.log(valid);
// 登录预验证
if(!valid)
{
return
}
const {data:res}=await this.$http.post('login',this.loginForm);
console.log(res);
if(res.meta.status!==200)
{
return console.log("登录失败")
}
else
{
return console.log("登录成功")
}
})
}
-
elementui 消息提示,将Message挂载在原型属性上,elementui 消息提示,将Message挂载在原型属性上,登录成功和错误都将给出弹框提示
-
将登录成功后的token,保存在客户端的sessionStorage中,因为项目中除了登录外的其他api接口,必须在登录后才能访问,且token只应在网站打开期间生效,所以将token保存sessionStorage中
-
通过编程式导航跳到后台主页,路由地址式/home
-
路由导航守卫控制访问权限,如果用户没有登录,但是直接通过url访问特定页面,需要重新导航到登录页面,于是为路由对象,添加beforeEach导航守卫,如果访问的是login,直接放行,如果没有token,强制跳转到登录页
-
退出功能 如果是基于token的方式实现退出比较简单,只需要销毁本地的token就可以了,这样后续的请求就不会携带有token,必须登录重新生成一个新的token才能访问页面。
-
在首页中布置退出按钮,添加退出方法。
-
提交登录模块代码,将代码提交到login分支后,切换到master分支,主动合并login分支
git checkout master
git merge login
2、主页
- 引入elementui布局,在plugins里注册
- element中每个组件名其实也是类名,可以用来做样式
- 需要授权的 API ,必须在请求头中使用
Authorization
字段提供token
令牌,所以需要通过axios请求拦截器添加token。保证拥有获取数据的权限。 - 在main.js里配置请求拦截器,下面是config内容,
axios.interceptors.request.use(config=>{
console.log(config);
return config
})
- <el-submenu :index=“item.id+’’” v-for=“item in menuList”:key=‘item.id’>里的index动态绑定,且接收的是字符串
- 将从后端获取的菜单渲染到页面上,并调整菜单,点击高亮和引入iconfont
- 设置左侧菜单折叠功能collapse,折叠动画collapse-transition
- 登录时重定向到welcome页面
- 将左侧菜单改造成路由连接,添加router开启router模式,然后改造index
- 给每个二级菜单绑定点击事件,保存当前跳转途径,再传递给menu,让选择的二级菜单保持高亮
//Home.vue
<template>
<el-container class="home-container">
<el-header>
<el-button type="info" @click="logout">退出</el-button>
</el-header>
<el-container>
<el-aside :width="isCollapse?'64px':'200px'">
<div class="toggle-button" @click="toggleCollapse">|||</div>
<el-menu background-color="#333744" text-color="#fff" active-text-color="#409Eff" unique-opened router="true" :collapse="isCollapse" :collapse-transition="false" :default-active="activePath">
<el-submenu :index="item.id+''" v-for="item in menuList" :key='item.id'>
<template slot="title">
<i :class="iconsObj[item.id]"></i>
<span>{{item.authName}}</span>
</template>
<!-- 二级菜单 -->
<el-menu-item :index="'/'+subItem.path" v-for="subItem in item.children" :key="subItem.index" @click="saveNavState('/'+subItem.path)">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{subItem.authName}}</span>
</template>
</el-menu-item>
</el-submenu>
</el-menu>
</el-aside>
<!-- 主体区域 -->
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<script>
export default {
created(){
this.getMenuList();
this.activePath=window.sessionStorage.getItem('activePath')
},
data()
{
return{
menuList:[],
iconsObj: {
'125': 'iconfont icon-user',
'103': 'iconfont icon-tijikongjian',
'101': 'iconfont icon-shangpin',
'102': 'iconfont icon-danju',
'145': 'iconfont icon-baobiao'
},
// 是否折叠
isCollapse: false,
// 被激活的链接地址
activePath: ''
}
},
methods:{
logout:function(){
window.sessionStorage.clear();
this.$router.push('/login');
},
async getMenuList()
{
const {data:res}=await this.$http.get('menus');
if(res.meta.status!==200)
return this.$message.error(res.meta.msg);
this.menuList=res.data;
console.log(res);
},
// 点击按钮,切换菜单的折叠与展开
toggleCollapse() {
this.isCollapse = !this.isCollapse
},
// 保存链接的激活状态
saveNavState(activePath) {
window.sessionStorage.setItem('activePath', activePath)
this.activePath = activePath
}
}
}
</script>
<style lang="less" scoped>
.home-container {
height: 100%;
}
.el-header {
background-color: #373d41;
display: flex;
justify-content: space-between;
padding-left: 0;
align-items: center;
color: #fff;
font-size: 20px;
> div {
display: flex;
align-items: center;
span {
margin-left: 15px;
}
}
}
.el-aside {
background-color: #333744;
.el-menu {
border-right: none;
}
}
.el-main {
background-color: #eaedf1;
}
.iconfont {
margin-right: 10px;
}
.toggle-button {
background-color: #4a5064;
font-size: 10px;
line-height: 24px;
color: #fff;
text-align: center;
letter-spacing: 0.2em;
cursor: pointer;
}
</style>
2.1、用户列表
- 在路由中注册用户列表组件,然后绘制基本的ui结构,按需导入element,引入输入框,然后使用elementui里的布局调整间隔
- 请求用户列表数据,然后数据渲染
- 状态列和操作列用作用域操作,获取当前行数据在渲染
- tooltip是上面出现提示
- 监听分页请求,
handleSizeChange(newSize)
// 监听 pagesize 改变的事件
handleCurrentChange(newPage)
// 监听 页码值 改变的事件,然后根据最新的页码和每页显示条数更新数据和重新发起请求 - 用户状态的修改,监听switch开关的开启和关闭,
@change="userStateChanged(scope.row)"
// 监听switch开关的变化
userStateChanged(userinfo)
{
console.log(userinfo);
}
}
7. 实现查询功能,给输入框绑定data中的query,再给搜索图标绑定方法,点击发送查询请求
8. 给输入框添加清空属性,clearable,然后清空后再刷新页面,通过elementui里的InputEvents中的clear, @clear="getUserList"
9. 添加用户功能,添加dialog对话框,布置输入框设置检验规则,
10.实现自定义规则 先定义校验规则,再在具体的校验中使用validator指向,regEmail.test(value)
test 方法返回一个 Boolean 值,它指出在被查找的字符串中是否存在模式。
rgexp.test(str)
11. 实现添加用户表单关闭后重置表单的操作,通过 resetFields()
12. 添加用户的预验证功能
addUser(){
this.$refs.addFormRef.validate(vaild=>{
console.log(vaild);
})
}
}
当输入不合法还点击提交的时候校验失败vaild为false
-
校验通过后,发起请求,添加一个用户
-
添加修改用户信息的提示框,拿到用户对应行的数据拿到id,进行查询拿到用户信息
3、权限管理
3.1、权限列表
- 新建rights.vue组件,配置路由规则
- 页面基本布局,添加面包屑导航和卡片
- 请求权限列表数据,渲染到卡片中,在卡片中增加el-table,绑定数据源为rightsList,在el-table中增加列,label为列名,props接受绑定数据源具体的数据名
- el-table中添加属性border给表格添加边框,stripe增加隔行变色属性
- 通过作用域插槽,拿到行数据,然后渲染等级标签
3.2、角色列表
- 新建Roles.vue组件,配置路由规则
- 页面基本布局,添加面包屑导航和卡片
- 放置一个添加角色按钮,在卡片中放一行再放置按钮
- 请求权限列表数据,渲染到卡片中,在卡片中增加el-table,绑定数据源为rightsList,在el-table中增加列,label为列名,props接受绑定数据源具体的数据名
- 在每列前再添加一个展开列,
<el-table-column type="expand"></el-table-column>
- 在展开列中渲染子数据,一级标签二级标签三级标签
- 在全局样式中设置最小宽度,防止变形
- 给每个标签绑定关闭时的方法