【VUE项目实战】17、通过接口获取菜单并渲染

接上篇《16、主页Header和左侧菜单栏布局
上一篇我们编写了头部Header和左侧菜单栏的布局样式,本篇我们来通过接口获取菜单数据,并重新加载菜单至左侧菜单栏。

一、获取菜单数据的权限

我们需要通过接口获取菜单数据,而菜单必须是在登录之后才能访问的,所以未登录前直接访问菜单接口是会被拒绝。那么登录之后又如何让接口认定前端已有权限获取数据了呢?我们回顾一下API文档中的注意事项:

即我们获取需要授权的API的数据时,必须将我们登录时获取的token令牌,封装到http请求头的Authorization字段中。 

那么我们如何给每一个请求的Authorization字段添加token值呢?如果每个数据请求方法都自己加,显然十分繁琐和冗余。我们可以使用axios的请求拦截器添加token,即在每个http请求发出之前,进行再次封装,将token值封装进去之后,再进行请求。

下面是使用拦截器的样例代码:

//axios请求拦截
axios.interceptors.request.use(config => {
  //为请求头对象,添加Token验证的Authorization字段
  config.headers.Authorization = window.sessionStorage.getItem('token');
  return config;
})

我们可以调用axios的interceptors属性,该属性有一个request成员,这个request就是一个请求拦截器。它的use函数为请求拦截器挂载一个回调函数,在使用axios进行网络请求时,会优先调用use函数。
所以我们需要实现,请求在到达服务器之前,使用对http请求头进行一个预处理,将token封装到请求头的Authorization属性中。

如何实现?我们在main.js中设置(之前的默认请求路径和$Http对象的指定都是在这个文件):

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import './plugins/element.js'
//导入全局样式表
import './assets/css/global.css'
import axios from 'axios'
axios.defaults.baseURL = 'https://127.0.0.1:8888/api/private/v1/' //定义根路径
//为axios添加拦截器
axios.interceptors.request.use(config =>{
  console.log(config);
  return config;//最后必须返回config
})
Vue.prototype.$http = axios //在原型链上给$http赋值为axios对象
 
Vue.config.productionTip = false
 
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

我们先打印出来config,看看是个什么东西:

我们可以看到之前指定的beseURL在config对象中是有的,然后其中的headers,就是http请求的头对象,目前是有一个“Accept”属性,用来指定请求的文本类型等,我们可以为其添加一个Authorization属性。

修改use函数,为请求头封装token:

//为axios添加拦截器
axios.interceptors.request.use(config =>{
  console.log(config);
  config.headers.Authorization = window.sessionStorage.getItem('token');
  return config;//最后必须返回config
})

然后我们来测试一下,Authorization中是否会封装进token。
首先点击Home页的退出或清除浏览器缓存,让系统处于未登录状态。在登录页面点击登录,此时我们F12查看网络请求,login的请求中,Authorization是空的,那是因为我们当前还未获取到token:

我们下面编写获取菜单的代码,在请求菜单的时候,我们看看Authorization是否有值。

二、获取菜单数据

首先我们来看一下左侧菜单栏的API文档:

我们请求的是“menu”服务,而这个服务返回的是一个大的data对象和一个meta对象,其中meta是我们请求的结果对象,status是200的话,代表我们请求成功。data是服务器返回的菜单列表,其中id是菜单的主键,authName是菜单的名称。path是菜单的链接路径,children是菜单的子菜单,如果没有就是一个空数组。

下面我们在Home.vue中编写加载菜单的代码。因为菜单是在页面开始加载的时候就需要渲染上去,所以我们需要在生命周期函数created方法中定义获取菜单的方法:

<script>
export default {
  data(){
    return {
      //左侧菜单数据
      menuList:[]
    }
  },
  created(){
    this.getMenuList();
  },
  methods: {
    logout() {
      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);
    }
  },
};
</script>

我们通过接口获取菜单数据,如果获取不成功(status不是200),则弹出错误信息,如果获取成功,将data赋值给设置好的menuList变量。
我们登录后到Home页面,F12查看控制台打印的res对象:

可以看到结构如同API文档中的结构,一共有五个主菜单,其中每个菜单还有子菜单(Array的数量就是子菜单的数量)。

同时,我们可以看到Authorization对象是有值的,证明我们在请求菜单之前,已经试用axios的拦截器将token封装进去了:

三、渲染菜单结构

我们通过API接口获取到了菜单的数据,下面我们就要将菜单的数据渲染到左侧菜单栏,根据层架来加载菜单。

通过接口返回的data结构我们可以分析出,menuList对象的每一个子成员,都是一级菜单,而每一个一级菜单的children对象中,是二级菜单。所以我们使用两层for循环即可,一级for循环加载一级菜单,二级for循环加载二级菜单,实现如下:

<el-container>
  <!-- 侧边栏 -->
  <el-aside width="200px">
    <el-menu background-color="#333744" text-color="#fff" active-text-color="#ffd04b">
      <!-- 一级菜单 -->
      <el-submenu :index="item.id+''" v-for="item in menuList" :key="item.id">
        <!-- 一级菜单的模板区域 -->
        <template slot="title">
          <!-- 图标 -->
          <i class="el-icon-location"></i>
          <!-- 菜单名称 -->
          <span>{
   
   {item.authName}}</span>
        </template>
        <!-- 二级菜单 -->
        <el-menu-item :index="item.id+'-'+subItem.id" v-for="subItem in item.children" :key="subItem.id">
            <template slot="title">
                <i class="el-icon-menu"></i>
                <span slot="title">{
   
   {subItem.authName}}</span>
            </template>
        </el-menu-item>
      </el-submenu>
    </el-menu>
  </el-aside>
  <!-- 右侧内容主体 -->
  <el-main>Main</el-main>
</el-container>

首先是一级for循环,在el-submenu上,这里必须指定index为动态数据,以id为主(因为只接收字符串,所以id后加了空串),这样会避免打开一个菜单时所有菜单一起打开(因为index相同)。然后制定for循环menuList的data数据,key是data成员的id。然后在一级菜单的文本区域设置authName属性。
二级菜单的for循环,在el-menu-item上,循环的是data每个子成员的children属性,同样的设置index和key,以及菜单名。

最终效果:

至此,左侧菜单的加载和渲染就编写完毕了。

下一篇我们继续来美化左侧菜单。

参考:黑马程序员(www.itheima.com)Vue项目实战教学视频
转载请注明出处:https://blog.csdn.net/u013517797/article/details/120611652

Guess you like

Origin blog.csdn.net/u013517797/article/details/120611652