在之前我们实现了注册登录功能,接下来就是管理平台侧面菜单栏以及平台首页的实现。
在实现功能之前,还是需要先整理一下实现的思路。
个人中心:目标(将用户信息存储到vuex中)
实现步骤:1、定义一个接口方法,用于请求用户信息
2、使用接口方法+actions获取用户的基本信息
3、在全局前置守卫, 做判断, 有token但是无userInfo信息, 才发请求拿用户信息
4、渲染用户信息
定义接口方法:
// 获取个人信息
export const userInfo = () => request({
url: '/my/userinfo'
//没有添加请求拦截的时候,需要在这里带上请求头信息,如果在请求拦截里统一封装了请求头这里就不需要再次书写了
// headers: {
// Authorization: store.state.token
// }
})
使用接口方法:
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import { userInfo } from '@/api/index'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
// 保存token字符串
token: '',
// 保存用户信息
userInfo: {}
// 保存菜单信息
// menu: {}
},
getters: {
// 定义并导出用户名和昵称
nickname: state => state.userInfo.nickname,
username: state => state.userInfo.username,
user_pic: state => state.userInfo.user_pic
},
mutations: {
// 存储token的方法
updateToken (state, val) {
state.token = val
}
},
actions: {
// 定义初始化用户基本信息的action函数
async initUserInfo (store) {
const { data: res } = await userInfo()
if (res.code === 0) {
store.commit('updateUserInfo', res.data)
}
}
},
modules: {
},
plugins: [createPersistedState()]
})
// vuex-persistedstate 对vuex内的数据进行持久化存储
全局前置守卫:
// 路由白名单
const whiteList = ['/login', 'register']
// 路由前置守卫
// next()如果强制切换路由,会再次走路由守卫再次匹配路由表
router.beforeEach((to, from, next) => {
const token = store.state.token
// 有token代表登录了
if (token) {
if (!store.state.userInfo.username) {
// 有token在请求信息
store.dispatch('initUserInfo')
}
next()
} else {
// 未登录,跳转到登录页
if (whiteList.includes(to.path)) {
next()
} else {
next('/login')
}
}
})
渲染用户信息:
<div class="user-box">
<!-- 有头像信息就展示,没有就选择默认 -->
<img :src="user_pic" alt="" v-if="user_pic" class="img">
<img class="img" src="https://img0.baidu.com/it/u=2880518663,495982857&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500" alt="" v-else>
<span>欢迎{{nickname || username }}</span>
<!-- 直接用的方法{{$store.state.userInfo.nickname}} {{$store.getters.nickname}}-->
</div>
实现效果:
侧面菜单栏:1、样式布局
2、封装接口请求方法
3、调用接口,铺设数据
样式布局:
<el-aside width="200px">
<!-- 侧边栏导航菜单 -->
<!-- // 获取路径,相应的菜单栏高亮 -->
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
background-color="#23262e"
text-color="#fff"
active-text-color="#409eff"
router
unique-opened>
</el-menu>
</el-aside>
封装接口请求:
// 获取侧边栏数据
export const asideData = () => request({
url: '/my/menus'
})
调用接口请求并铺设数据:
调用接口:
async getMenu () { const { data: res } = await asideData() console.log(res) // 保存菜单 this.menu = res.data }
保存接口请求的菜单数据:
data () { return { menu: [] } }
铺设数据:
<!-- 需要用template包裹 --> <template v-for="item in menu"> <el-menu-item :index="item.indexPath" v-if="!item.children" :key="item.indexPath"> <i :class="item.icon"></i>{{item.title}} </el-menu-item> <el-submenu :index="item.indexPath" v-else :key="item.indexPath"> <template slot="title"> <i :class="item.icon"></i> <span>{{item.title}}</span> </template> <el-menu-item :index="item1.indexPath" v-for="item1 in item.children" :key="item1.indexPath"> <i :class="item1.icon"></i> {{item1.title}} </el-menu-item> </el-submenu> </template>
实现效果: