1. 组件缓存
1.1 介绍
先来看一个问题?
从首页切换到我的,再从我的回到首页,我们发现首页重新渲染原来的状态没有了。
首先,这是正常的状态,并非问题,路由在切换的时候会销毁切出去的页面组件,然后渲染匹配到的页面组件。
但是我想要某些页面保持状态,而不会随着路由切换导致重新渲染。
1.2 使用 keep-alive 缓存组件
官方文档:在动态组件上使用 keep-alive
<keep-alive>
主要用于保留组件状态或避免重新渲染,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
(1)组件缓存不是持久化,它只是在应用运行期间不会重新渲染,如果页面刷新还是会回到初始状态。
(2)<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
(3)<keep-alive>
要求被切换到的组件都有自己的名字,不论是通过组件的 name
选项还是局部/全局注册。
(4)组件生命周期钩子和缓存
具体使用要根据实际情况来处理,在我们项目后续的业务功能中慢慢体会。
(5)include
和 exclude
属性允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。
<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
<component :is="view"></component>
</keep-alive>
<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
<component :is="view"></component>
</keep-alive>
<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
<component :is="view"></component>
</keep-alive>
- 匹配首先检查组件自身的
name
选项,如果name
选项不可用,则匹配它的局部注册名称 (父组件components
选项的键值)。匿名组件不能被匹配。 - 参考阅读
- 在动态组件上使用 keep-alive
- 内置的组件 keep-alive
1.3 项目中的缓存配置
参考链接:
- https://juejin.cn/post/6844903887040675854vue项目实现缓存的最佳方案https://juejin.cn/post/6844903887040675854
① 在 App.vue
对根路由组件启用组件缓存
② 在 views/tabbar/index.vue
对子路由也启用组件缓存
1.4 解决缓存之后我的页面用户数据不更新问题
将原来 created 中的逻辑代码写到 activated 中:
activated () {
if (this.user) {
this.loadUserInfo()
}
},
2. 处理 token 过期
参考链接:
- vue中Axios的封装和API接口的管理
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 响应成功进入这个函数
return response;
}, async function (error) {
// 响应失败进入这个函数,超出 2.xx 的状态码都会进入这里
// console.log(error.response.status)
const status = error.response.status
if (status === 400) {
// 客户端请求参数异常
Toast.fail('客户端请求参数异常。')
} else if (status === 401) { // token 无效,过期
// 如果没有 user或者 user.token,直接去登录
const user = store.state.user
if (!user || !user.token) {
// replace 方法不会形成历史记录,push 会形成历史记录
redirectLogin()
return
}
// 使用 refresh_token,则请求获取新的 token
try {
const res = await refreshTokenRequest(user.refresh_token)
// 拿到新的 token 之后把它更新到容器之中
user.token = res.data.data.token
store.commit('setUser', user)
// 把失败的请求重新发出去 error 是本次请求的相关配置对象
return axios(error.config)
} catch (err) {
// token 刷新失败,直接跳转登录页面
redirectLogin()
}
} else if (status === 403) {
Toast.fail('没有权限操作。')
} else if (status >= 500) {
// 服务端异常
Toast.fail('服务端异常。')
}
return Promise.reject(error);
});
const refreshTokenRequest = (refresh_token) => {
return axios({
url: 'https://toutiao.itheima.net/v1_0/authorizations',
method: 'PUT',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: 'Bearer' + ' ' + refresh_token
}
})
}
const redirectLogin = () => {
// router.currentRoute 当前路由对象,和你在组件中访问的 this.$route 是同一个东西
// query 参数的数据格式就是:?key=value&key=value
router.replace({
name: 'login',
query: {
redirect: router.currentRoute.fullPath
}
})
}
3. 登录成功跳转回原来页面
4. 处理页面的访问权限
① 给需要登录状态才能访问的页面路由对象的 meta 中添加配置属性
② 通过路由拦截器统一校验
- 路由拦截器