主页权限验证
前置守卫开启进度条,后置守卫关闭进度条
import router from '@/router'
import nProgress from 'nprogress'// 导入进度条(模板自带)
import 'nprogress/nprogress.css'// 导入进度条样式(模板自带)
// 前置守卫
// 到哪里,去哪里,做什么
router.beforeEach((to, from, next) => {
// 开启进度条
nProgress.start()
})
// 后置守卫
router.afterEach(() => {
// 关闭进度条
nProgress.done()
})
如果有token,如果跳转登录页面情况
// 前置守卫
// 到哪里,去哪里,做什么
router.beforeEach((to, from, next) => {
// 开启进度条
nProgress.start()
if (// 存在token
store.getters.token) {
if (to.path === '/login') {
// 跳转首页
next('/')
} else {
next()// 到其他页面,放行
}
} else {
// 没有token
next()
}
})
没有token
声明白名单
// 声明白名单
const whiteList = ['/login', '404']
// 到哪里,去哪里,做什么
router.beforeEach((to, from, next) => {
// 开启进度条
nProgress.start()
if (// 存在token
store.getters.token) {
if (to.path === '/login') {
// 跳转到主页
next('/') // 中转到主页
// next(地址)并没有执行后置守卫
nProgress.done()
} else {
next()// 到其他页面,放行
}
} else {
// 没有token
if (whiteList.includes(to.path)) {
next()
} else {
next('/login') // 中转到登录页
nProgress.done()
}
}
})
总结
登录后获取用户资料
index.vue里有token的前提下调用action异步方法
created() {
// 调用action
this.$store.dispatch('user/getUserInfo')
}
}
store/user.js里存放action
1.先导入接口,并声明一个对象来存储用户基本资料状态
import { login,getUserInfo } from '@/api/user'
// 用来存放数据
const state = {
token: getToken(),// 调用加括号,从缓存中读取初始值
userInfo:{}//声明一个对象来存储用户基本资料状态
}
2.利用mutations修改userInfo的值
// 用来修改数据,要修改state里的数据,必须通过mutations
const mutations = {
setToken(state, token) {
state.token = token
// 同步到缓存
setToken(token)
},
removeToken() {
// 删除vuex的token
state.token = null
removeToken()
},
setUserInfo(state,userInfo){
state.userInfo = userInfo
}
}
3.actions调用接口,获取数据并通过context提交给mutation
const actions = {
// context上下文,传入参数
async login(context, data) {
console.log(data)
// 点击调用登录接口,成功执行await后的内容
const token = await login(data)
// 提交mutations里的数据,调用context里的默认方法
context.commit('setToken', token)
},
// action
async getUserInfo(context) {
// 获取接口信息
const result = await getUserInfo()
context.commit('setUserInfo', result)
}
}
api/user.js里封装接口
export function getUserInfo() {
return request({
url: '/sys/profile'
})
}
调整action位置
getter.js里封装userId
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
userId: state => state.user.userInfo.userId,
avatar: state => state.user.avatar,
name: state => state.user.name
}
export default getters
permission.js
if (!store.getters.userId) { await store.dispatch('user/getUserInfo') }
next()// 到其他页面,放行
}
} else {
// 没有token
if (whiteList.includes(to.path)) {
next()
} else {
next('/login') // 中转到登录页
nProgress.done()
}
}
显示用户头像、名称
根据传过来的数据显示头像和名称
1.通过getters向外暴露用户头像和信息
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
userId: state => state.user.userInfo.userId,
avatar: state => state.user.userInfo.avatar, // 用户头像
name: state => state.user.userInfo.name// 用户名称
}
export default getters
2.找组件
先引入
import { mapGetters } from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import Hamburger from '@/components/Hamburger'
export default {
computed: {
...mapGetters([
'sidebar',
'avatar',
'name'
])
}
使用
<!--头像-->
<img :src="avatar" class="user-avatar">
<!--用户名称-->
<span>{{ name }}</span>
调整样式
.avatar-wrapper {
margin-top: 5px;
position: relative;
display: flex;
align-items: center;
.name{
margin-right: 10px;
font-size: 16px;
}
.el-icon-setting{
font-size: 20px;
}
处理用户头像为空
1.v-if 和v-else
2.设置样式
.username{
width: 30px;
height: 30px;
line-height: 30px;
align-items: center;
background-color: aqua;
color: #fff;
border-radius: 50%;
margin-right: 4px;
}
3.当用户姓名为空时,使用可选链(需要升级版本)
处理token失效
store/user.js声明一个提出登录的actions
logout(context) {
context.commit('removeToken')
// 调用setUserInfo,传进去空对象,以清除用户信息
context.commit('setUserInfo', {})
}
request.js跳转
if (error.response.status === '401') {
Message({ type: 'warning', message: 'token超时' })
store.dispatch('user/logout')// 调用action退出登录
// 主动跳转到登录页
router.push('/login')
return Promise.reject(error)
}
Message({ type: 'error', message: error.message })
return Promise.reject(error)
退出登录
async logout() {
this.$store.dispatch('user/logout')
this.$router.push('/login')
}
显示修改密码弹层
<!--放置dialog-->
<!--.sync,可以接收子组件传过来的事情和值-->
<el-dialog width="500px" title="修改密码" :visible.sync="showDialog">
<el-form />
</el-dialog>
表单结构
<el-dialog width="500px" title="修改密码" :visible.sync="showDialog">
<!--放置表单-->
<el-form label-width="120px">
<el-from-item label="旧密码">
<el-input show-password size="small" />
</el-from-item>
<el-from-item label="新密码">
<el-input show-password size="small" />
</el-from-item>
<el-from-item label="重置密码">
<el-input show-password size="small" />
</el-from-item>
<el-form-item>
<el-button type="primary" size="mini">确认</el-button>
<el-button size="mini">取消</el-button>
</el-form-item></el-form>
</el-dialog>
表单校验(prop与rules有关,v-model与数据绑定有关)
<el-dialog width="500px" title="修改密码" :visible.sync="showDialog">
<!--放置表单-->
<el-form ref="passForm" label-width="120px" :rules="rules" :model="passForm">
<el-from-item label="旧密码" prop="oldPassword">
<el-input v-model="passForm.oldPassword" show-password size="small" />
</el-from-item>
<el-from-item label="新密码" prop="newPassword">
<el-input v-model="passForm.newPassword" show-password size="small" />
</el-from-item>
<el-from-item label="重置密码" prop="confirmPassword">
<el-input v-model="passForm.confirmPassword" show-password size="small" />
</el-from-item>
<el-form-item>
<el-button type="primary" size="mini">确认</el-button>
<el-button size="mini">取消</el-button>
</el-form-item></el-form>
</el-dialog>
变量准备(rules在data里)
data() {
return {
showDialog: false,
passForm: {
oldPassword: '',
newPassword: '',
confirmPassword: ''
},
rules: {
oldPassword: [],
newPassword: [],
confirmPassword: []
}
}
},
校验规则
判断两次密码是否相同:用了自定义校验,注:必须使用箭头函数,否则this不能指向组件实例
rules: {
oldPassword: [{ required: true, message: '旧密码不能为空', trigger: 'blur' }], // 旧密码
newPassword: [{ required: true, message: '新密码不能为空', trigger: 'blur' }, {
trigger: 'blur',
min: 6,
max: 16,
message: '新密码的长度为6-16位之间'
}], // 新密码
confirmPassword: [{ required: true, message: '重复密码不能为空', trigger: 'blur' }, {
trigger: 'blur',
validator: (rule, value, callback) => {
// value
if (this.passForm.newPassword === value) {
callback()
} else {
callback(new Error('重复密码和新密码输入不一致'))
}
}
}] // 确认密码字段
}
}
},
总结
确认按钮
先绑定事件,之后调用接口(传参时就多不就少,注意async)
btnOk() {
this.$refs.passForm.validator(async(isOk) => {
if (isOk) {
// 调用接口
// 传收集来的值
await updatePassword(this.passForm)
// 成功后执行重置表单,不成功不用管
this.$refs.passForm.resetFields()
// 关闭弹层
this.showDialog = false
}
})
}
优化:
this.$refs.passForm.resetFields()
// 关闭弹层
this.showDialog = false
这两句代码与关闭按钮的一致,所以直接调用关闭按钮
btnOk() {
this.$refs.passForm.validator(async(isOk) => {
if (isOk) {
// 调用接口
// 传收集来的值
await updatePassword(this.passForm)
// 成功后执行重置表单,不成功不用管
this.$refs.passForm.resetFields()
// 关闭弹层
// this.showDialog = false
// this.$message.success('修改成功')
this.btnCancel()
}
})
}