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
- 特性:关闭浏览器后,会话失效,再次打开浏览器,重新登录。
- cookie
- 注意:后台对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-默认配置选项
- 请求的时候配置选项
- baseURL 基准地址 http://ttapi.research.itcast.cn/mp/v1_0/
- headers 配置请求头信息
- Authorization
- Bearer + 空格 + token信息
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()