Vue + ElementUI 实现后台管理系统模板 -- 前端篇(八):引入 vue-router 进行路由管理、模块化封装 axios 请求

目录

一、引入 vue-router 进行路由管理

1、简单了解下

 2、项目中使用

3、导航守卫、路由元信息

二、模块化封装 axios 请求

1、简介

2、代码实现


一、引入 vue-router 进行路由管理

1、简单了解下

  之前在 搭建基本页面时,已经简单使用过,这里再深入了解一下。
1)文件格式如下
  由于创建项目时,指定了 router,所以 vue-cli 自动生成了 router 文件夹以及相关的 js 文件。

 

2)手动引入 router(可选操作)。

 若初始化项目时未指定 router,可以自己手动添加 router。

 【router 中文文档:】 https://router.vuejs.org/zh/

 2、项目中使用

(1)简介
此项目是单页面应用,通过 vue-router 将 各个组件(components)映射到指定位置,实现页面切换的效果。
之前定义基本页面时,已经简单应用了 router。

(2)代码如下:
  根据路径可以进行路由匹配,也可根据 name 属性去定位路由。
其中:
  component 采用路由懒加载的形式( () => import() ),路由被访问时再加载。
  path: '/' 表示项目根路径。
  redirect 表示跳转到另一个路由。
  name: "Login" 表示路由名,可以根据 name 定位路由。
  path: "*" 表示全匹配,一般写在路由规则的最后一个(用于路径不存在时跳转到一个指定页面)。

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";

Vue.use(Router);

const routes = [{
    path: "/",
    name: "home",
    component: Home,
    children: [{
      path: "/about",
      name: "About",
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () =>
        import( /* webpackChunkName: "about" */ "./views/About.vue")
    }, ]
  },

  {
    path: "/login",
    name: "Login",
    component: () => import("./views/login.vue")
  },
  {
    path: "*",
    name: "404",
    component: () => import('./views/404.vue')
  },
]
const router = new Router({
  routes, // 用于定义 路由跳转 规则
  mode: "history", // mode 用于去除地址中的 #
  base: process.env.BASE_URL,
  scrollBehavior: () => ({ // scrollBehavior 用于定义路由切换时,页面滚动。
    y: 0
  })
});
// 解决相同路径跳转报错
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => {
    err
  })
}
export default router

3、导航守卫、路由元信息

(1)简介
  导航守卫适用于 路由变化时。即当路由变化时,会触发导航守卫。
  路由元信息 可以用于定义路由独有的信息(meta)。


注: 同一个组件切换时,参数改变不会触发导航守卫(复用组件)。可以通过 watch 监听 $route 对象的变化来定义导航守卫,或者 直接使用 beforeRouteUpdate 来进行导航守卫(组件内守卫)。

(2)全局前置守卫(beforeEach)
  使用 beforeEach 可以定义一个全局前置守卫,路由跳转前会触发。
其有三个参数:
  to:一个路由对象,表示即将进入的 目标路由对象。
  from:一个路由对象,表示当前路由 离开时的路由对象。
  next:一个方法(不能少,确保路由能够跳转出去。
      next() 表示执行下一个守卫规则,若所有规则执行完毕,则结束并跳转到指定路由。
      next({path: ''}) 或者 next({name: ''}) 表示指定路径跳转。

const router = new VueRouter({ ... })

router.beforeEach((to, from, next) => {
  // ...
})

(3)路由元信息
  定义路由规则时,可以通过 meta 指定路由的元信息。
  通过 router对象.meta 可以获取到某个 router对象 的 meta 信息,并根据其进行处理。 

const router = new VueRouter({
  routes: [
    {
      path: '/foo',
      component: Foo,
      children: [
        {
          path: 'bar',
          component: Bar,
          meta: { requiresAuth: true }
        }
      ]
    }
  ]
})

(4)项目中使用
  进入主页面后,当 token 过期或不存在时,需要跳转到登录页面重新登录。
  使用 导航守卫,每次路由跳转前,确定 token 是否存在。可以使用 beforeEach 定义全局守卫,也可以使用 beforeEnter 为某个路由定义独有守卫。
  此处演示使用 beforeEach 定义全局守卫。

Step1:
  修改 Login.vue 登录逻辑,保存 token 值。
  之前将 cookie 相关的操作保存在 /utils/auth.js 中,需要引入该 js。

import { setToken } from '@/utils/auth.js';
 // 提交表单
    submitForm() {
      // 登录
      this.$request({
        url: '/auth/token',
        method: 'post',
        data: this.loginForm,
      }).then((res) => {
        if (res.data.code === 0) {
          this.$message({ message: '登录成功', type: 'success' });
           // 保存 token 值
          setToken(res.data.token);
          this.updateName(this.loginForm.username);
          this.$router.push({
            name: 'About',
          });
        }
      });
    },

完整代码:


  <div class="login" :style="{ backgroundImage: 'url(' + loginBg + ')' }">
    <div class="wrapper">
      <h3 class="head">CMS后台管理系统</h3>
      <el-form :rules="rules" size="medium" :model="loginForm" ref="loginForm" class="login-form" @keyup.enter.native="submitForm">
        <el-form-item prop="userName">
          <el-input size="medium" type="text" v-model.trim="loginForm.userName" placeholder="请输入用户名" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item prop="password">
          <el-input size="medium" type="password" v-model.trim="loginForm.password" placeholder="请输入密码" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button size="medium" style="width: 100%" type="primary" @click="submitForm">立即登录</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>
<script>
import { setToken } from '@/utils/auth.js';
import { mapActions } from 'vuex';
export default {
  data() {
    return {
      loginBg: require('../assets/images/login-bg.png'),
      loginForm: { userName: '', password: '' },
      rules: {
        userName: [{ required: 'true', message: '账户不能为空', trigger: 'blur' }],
        password: [{ required: 'true', message: '密码不能为空', trigger: 'blur' }],
      },
    };
  },
  methods: {
    ...mapActions('user', ['updateName']),
    submitForm() {
      // 登录
      this.$request({
        url: '/auth/token',
        method: 'post',
        data: this.loginForm,
      }).then((res) => {
        if (res.data.code === 0) {
          this.$message({ message: '登录成功', type: 'success' });
          // 保存 token 值
          setToken(res.data.token);
          this.updateName(this.loginForm.userName);
          this.$router.push({
            name: 'About',
          });
        }
      });
    },
  },
};
</script>
<style scoped>
.login {
  height: 100vh;
  background-size: 100% 100%;
}
.wrapper {
  position: absolute; /* fixed 同理 */
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 20rem;
}
.head {
  margin-bottom: 25px;
  color: #fff;
  font-size: 24px;
}
</style>

 Step2:
  修改路由。
  定义路由元信息(meta)。meta 用于定义路由元信息,其中 isRouter 用于指示是否开启路由守卫(true 表示开启)。并按照aside.vue新增路由及文件Echart.vue及Ueditor.vue

const routes = [{
    path: "/",
    name: "Home",
    component: Home,
    children: [{
        path: "/about",
        name: "About",
        meta: {
          name: '关于我们',
          isRouter: true
        },
        component: () =>
          import( /* webpackChunkName: "about" */ "./views/About.vue")
      },
      {
        path: '/demo/echart',
        name: 'Echarts',
        component: () => import('@/views/echart/Echarts.vue'),
        meta: {
          isRouter: true
        }
      },
      {
        path: '/demo/ueditor',
        name: 'Ueditor',
        component: () => import('@/views/ueditor/Ueditor.vue'),
        meta: {
          isRouter: true
        }
      }
    ]
  },
  {
    path: "*",
    name: "404",
    component: () => import("./views/404.vue")
  },
  {
    path: "/login",
    name: "Login",
    component: () => import("./views/login.vue")
  }
]

Step3:
  添加全局守卫(beforeEach)。
  当 isRouter 为 true 时,才会去校验 token,token 校验失败则跳转到 Login 页面重新登录。

// 添加全局路由导航守卫
router.beforeEach((to, from, next) => {
    // 当开启导航守卫时,验证 token 是否存在。
    if (to.meta.isRouter) {
        // 获取 token 值
        let token = getToken()
        console.log(token)
        // token 不存在时,跳转到 登录页面
        if (!token || !/\S/.test(token)) {
            next({name: 'Login'})
        }
    }
    next()
})

Step4:
  完整 router 如下:

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";
import {
  getToken
} from "@/utils/auth.js";

Vue.use(Router);

const routes = [{
    path: "/",
    name: "Home",
    component: Home,
    children: [{
        path: "/about",
        name: "About",
        meta: {
          name: '关于我们',
          isRouter: true
        },
        component: () =>
          import( /* webpackChunkName: "about" */ "./views/About.vue")
      },
      {
        path: '/demo/echart',
        name: 'Echarts',
        component: () => import('@/views/echart/Echarts.vue'),
        meta: {
          isRouter: true
        }
      },
      {
        path: '/demo/ueditor',
        name: 'Ueditor',
        component: () => import('@/views/ueditor/Ueditor.vue'),
        meta: {
          isRouter: true
        }
      }
    ]
  },
  {
    path: "*",
    name: "404",
    component: () => import("./views/404.vue")
  },
  {
    path: "/login",
    name: "Login",
    component: () => import("./views/login.vue")
  }
]

const router = new Router({
  routes, // 用于定义 路由跳转 规则
  mode: "history", // mode 用于去除地址中的 #
  base: process.env.BASE_URL,
  scrollBehavior: () => ({ // scrollBehavior 用于定义路由切换时,页面滚动。
    y: 0
  })
});
// 添加全局路由导航守卫
router.beforeEach((to, from, next) => {
  // 当开启导航守卫时,验证 token 是否存在。
  if (to.meta.isRouter) {
      // 获取 token 值
      let token = getToken()
      console.log(token)
      // token 不存在时,跳转到 登录页面
      if (!token || !/\S/.test(token)) {
          next({name: 'Login'})
      }
  }
  next()
})
// 解决相同路径跳转报错
const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => {
    err
  })
}
export default router

Step5:
  测试一下。

  手动模拟 token 失效。token 失效后,点击菜单栏,路由会跳转到 登录界面。

二、模块化封装 axios 请求

1、简介

  前面封装了 axios,并在 main.js 中全局挂载,所以在组件中可以使用 $http 进行访问。
  但是每次请求的相关处理都会写在各个组件中,代码看上去不太美观,且不易维护。
  所以可以将请求根据功能、模块进行划分,并写在固定位置,在组件中引入这些模块即可。

2、代码实现

(1)按照功能将请求进行模块划分。
         比如:登录、登出的请求为 login.js,用户信息相关的请求为 user.js,菜单相关的请求为 menu.js。

import request from '@/utils/request'

export function getToken(data) {
  return request({
    url: '/auth/token',
    method: 'post',
    data
  })
}

(2)定义一个 index.js,引入 login.js 模块。

import * as login from './modules/login.js'
import * as user from './modules/user.js'

export default {
  login,
  user
}

 

 (3)在 main.js 中全局挂载。

import request from '@/api/index.js'
Vue.prototype.$request = request

 (4)修改 Login.vue 的登录逻辑,通过全局挂载的 $request调用 login 模块的 getToken 方法。

submitForm() {
      // 登录
      this.$request.login.getToken(this.loginForm).then((res) => {
        if (res.data.code === 0) {
          this.$message({ message: '登录成功', type: 'success' });
          // 保存 token 值
          setToken(res.data.token);
          this.updateName(this.loginForm.userName);
          this.$router.push({
            name: 'About',
          });
        }
      });
    },

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hongc93

感谢鼓励 继续航行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值