仿今日头条后台管理系统(三)

本文详细介绍了Vue Router的动态路由与激活样式保持,以及Axios在Vue项目中的高级配置,包括请求与响应拦截器的实现,确保了在刷新页面后仍能正确显示激活的导航菜单,并解决了token认证与会话状态保持的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

03-首页-导航菜单路由功能

  • 默认是没有点击切换路径
  • 是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转
  • 问题:刷新页面后 丢失激活的样式
    • 原因:default-active="/" 值是死的
    • 做法:获取当前地址栏的路径 设置给default-active 路径和菜单的index的值一致
<el-menu router></el-menu>

把index的值改成约定好的路由地址:

 <el-menu-item index="/">
          <i class="el-icon-s-home"></i>
          <span slot="title">首页</span>
        </el-menu-item>
        <el-menu-item index="/article">
          <i class="el-icon-document"></i>
          <span slot="title">内容管理</span>
        </el-menu-item>
        <el-menu-item index="/image">
          <i class="el-icon-picture"></i>
          <span slot="title">素材管理</span>
        </el-menu-item>
        <el-menu-item index="/publish">
          <i class="el-icon-s-promotion"></i>
          <span slot="title">发布文章</span>
        </el-menu-item>
        <el-menu-item index="/comment">
          <i class="el-icon-chat-dot-round"></i>
          <span slot="title">评论管理</span>
        </el-menu-item>
        <el-menu-item index="/fans">
          <i class="el-icon-present"></i>
          <span slot="title">粉丝管理</span>
        </el-menu-item>
        <el-menu-item index="/setting">
          <i class="el-icon-setting"></i>
          <span slot="title">个人设置</span>
        </el-menu-item>

动态绑定激活的菜单

<el-menu  :default-active="$route.path"></el-menu>
//显示当前的路径

04-首页-404页面

  • 什么时候显示404页面?
    • 当你约定的路由规则中没有对应的path,认为当前地址是404。
    • 先定义的路由规则会先匹配,如果走到最后一个路由,发现没有对应的规则。
    • 处理成404页面即可。
<template>
  <div class='container'></div>
</template>

<script>
export default {}
</script>

<style scoped lang='less'>
.container{
  position: absolute;
  width: 100%;
  height: 100%;
  background: url(../../assets/images/404.png) no-repeat center / cover;
}
</style>

router/index.js 最后加一个规则

routes: [
    { path: '/login', name: 'login', component: Login },
    {
      path: '/',
      component: Home,
      children: [
        { path: '/', name: 'welcome', component: Welcome },
        { path: '/article', name: 'article', component: Article }
      ]
    },
+    // 处理404
+    { path: '*', name: '404', component: NotFound }
  ]

05-接口-token认证问题

GET http://ttapi.research.itcast.cn/mp/v1_0/articles 401 (UNAUTHORIZED)
  • 报错:没有认证
  • 怎么认证:在请求的时候,在头部需要加上一个字段:
    • Authorization
    • 值:是你登录的时候返回的token信息
  • 登录之后,需要保存token
  • 在调用其他的接口,需要认证
    • 请求头:Authorization:Bearer + 空格 + token信息

07-登录-保持会话状态

  • 其实就是登录后保存 用户信息 在浏览器端
    • cookie
      • 在某一个时间后失效
    • localStorage
      • 永久生效
    • sessionStorage
      • 特性:关闭浏览器后,会话失效,再次打开浏览器,重新登录。
  • 注意:后台对token也有控制,2小时就失效。
// store/index.js 模块  获取用户  设置用户
// 存储信息的时候:
// 1. 约定信息的KEY是什么  hm-toutiao-77-user
// 2. 存储信息的值是什么   用户信息对象 字符串格式json
const KEY = 'hm-toutiao-77-user'

export default {
  setUser (user) {
    // 存储用户信息到sessionStorage
    window.sessionStorage.setItem(KEY, JSON.stringify(user))
  },
  getUser () {
    // 获取用户信息从sessionStorage
    return JSON.parse(window.sessionStorage.getItem(KEY) || '{}')
  }
}

保存用户信息: views/login/index.vue

login () {
      // 对整个表单进行校验
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          // 请求登录接口
          this.$http
            .post(
              'http://ttapi.research.itcast.cn/mp/v1_0/authorizations',
              this.loginForm
            )
            .then(res => {
              // res 响应对象   包含响应主体
              // console.log(res.data)
+              // 存储用户信息
+              store.setUser(res.data.data)
              // 跳转去首页
              this.$router.push('/')
            })
            .catch(() => {
              // 错误提示提示
              this.$message.error('手机号或验证码错误')
            })
        }
      })
    }

08-登录-拦截未登录路由跳转

  • 除登录路由外,所有的路由跳转前,判断是否登录过。
    • 判断 本地存储 是否存储了用户信息
    • 如果存储 意味登录了 放行
    • 如果没有 意味没登录 拦截到登录路由
  • 怎么监听到 跳转路由前
    • 技术:路由导航守卫
// 路由实例
const router = new VueRouter({ ... })
// 提供函数 beforeEach 前置守卫
router.beforeEach((to, from, next) => {
    // to 去的路由对象 from  来自哪里路由对象
    // 做事情,获取用户信息
    // 判断 是否登录  如果登录 放行 next()   拦截登录 next('/login')
    // 注意 排除登录路由
})

最终的代码:router/index.js

// 前置导航守卫
router.beforeEach((to, from, next) => {
  // // 1. 判断是不是登录路由
  // if (to.path === '/login') return next()
  // // 2. 判断是否登录
  // if (!store.getUser().token) return next('/login')
  // // 3. 放行
  // next()
  if (to.path !== '/login' && !store.getUser().token) return next('/login')
  next()
})

09-axios-默认配置选项

api/index.js

// 配置一个axios  导出一个配置好的axios
import axios from 'axios'
import store from '@/store'

// 进行配置
axios.defaults.baseURL = 'http://ttapi.research.itcast.cn/mp/v1_0/'
axios.defaults.headers = {
  Authorization: `Bearer ${store.getUser().token}`
}

// 进行导出
export default axios

main.js 修改

+ import axios from '@/api'
Vue.prototype.$http = axios

场景:

  • 清除了token
  • 刷新页面 拦截登录
  • 登录成功 跳转首页
  • 点击内容管理
  • 请求的时候没有获取到token
  • 刷新才好使???
    • 登录的时候 有token吗 没有 如果此时去获取了token undefined
    • 登录成功后 存储了token 当是此时获取token的代码没有重新执行了 使用的还是之前获取的token undefined
    • 再次发请求的时候 是没携带token

预期:

  • 当你发请当前,重新获取token
  • 每一次在axios请求之前,获取token,给头部加token。

10-axios-请求拦截器

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    // 修改config,追加headers
    return config;
  }, function (error) {
    // 认为返回错误的promise对象
    return Promise.reject(error);
  });

  • api/index.js
// 配置一个axios  导出一个配置好的axios
import axios from 'axios'
import store from '@/store'

// 进行配置
axios.defaults.baseURL = 'http://ttapi.research.itcast.cn/mp/v1_0/'
// 只会执行一次
// axios.defaults.headers = {
//   Authorization: `Bearer ${store.getUser().token}`
// }
// 在每次请求之前,获取token信息,追加在headers中
// 请求拦截器:在每次请求前 做某一些事情
axios.interceptors.request.use((config) => {
  // 修改config
  config.headers = {
    Authorization: `Bearer ${store.getUser().token}`
  }
  return config
}, (error) => {
  // 错误处理
  return Promise.reject(error)
})

// 进行导出
export default axios

11-axios-响应拦截器

  • 当你请求的时候
    • 没有携带token
    • 带了token但是失效
    • 后台会响应:
      • 状态码是401
      • 跳转到登录页面
  • 响应拦截器:是每次响应到客户端的时候,拦截。
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    // 状态码是401  跳转到登录页面
    return Promise.reject(error);
  });

最终的代码:api/index.js

// 响应拦截器:在每次响应后 做某一些事情
axios.interceptors.response.use((res) => {
  // 成功的时候做一些事情
  return res
}, (err) => {
  // 失败的时候做一些事情
  // 获取响应状态码 err对象包含响应对象  err.response
  // 响应对象中包含状态码  err.response.status
  if (err.response.status === 401) {
    // 跳转到登录页面 this.$router.push('/login')
    // 方式1:
    // $router.push('/login') 其实 地址栏改成  #/login
    // location.hash = '#/login'
    // 方式2:
    // 此时没有vue实例,$router对象获取不到,通过router实例直接使用
    router.push('/login')
  }
  return Promise.reject(err)
})

12-axios-结合async与await使用

  • axios是基于promise封装的xhr请求
  • promise的更优雅的使用是结合async和await

异步操作:

  • jquery的ajax 还是要回调函数 弊端:回调地狱
  • axios的promise的请求 弊端:代码不够简洁
  • async与await是关键字 修饰异步函数 作用:使用同步的语法来书写异步的操作
    // 当请求了A接口的数据才能获取B接口的数据

    // xhr 发请求  
    // const xhr = new XMLHttpRequest()
    // xhr.open('get','http://localhost:3000/a')
    // xhr.send()
    // xhr.onload = function(){
    //   console.log(xhr.responseText)
    //   const xhr2 = new XMLHttpRequest()
    //   xhr2.open('get','http://localhost:3000/b')
    //   xhr2.send()
    //   xhr2.onload = function(){
    //     console.log(xhr2.responseText)
    //   }
    // }

    // promise 发请求
    // 怎么创建一个promise对象 const proimse = new Promise(回调函数)
    // Promise.reject() 返回一个失败的promise对象
    // Promise.resolve() 返回一个成功的promise对象
    // proimse.then(成功).catch(失败)
    const axios = (url) => {
      return new Promise((resolve, reject) => {
        // resolve 成功的时候应该调用的回调函数
        // reject 失败的时候应该调用的回调函数
        const xhr = new XMLHttpRequest()
        xhr.open('get', url)
        xhr.send()
        xhr.onload = function () {
          // 传参内容 将在then的时候使用
          resolve(xhr.responseText)
        }
        xhr.onerror = function () {
          reject('失败错误对象')
        }
      })
    }
    // axios('http://localhost:3000/a').then(data=>{
    //   console.log(data)
    //   return axios('http://localhost:3000/b')
    // }).then(data=>{
    //   console.log(data)
    // })

    // async 与 await 的使用只能结合promise

    // 返回值是 promise 对象 加上await后返回是then的回调参数
    const getData = async () => {
      const a = await axios('http://localhost:3000/a')
      const b = await axios('http://localhost:3000/b')
      console.log(a)
      console.log(b)
      // await is only valid in async function
      // awiat的使用必须在async修饰的函数内使用
    }
    getData()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值