一、内容概要
以前写过一篇Vue.js单页应用实现前进刷新后退不刷新博客,但在实际的使用的中感觉配置很麻烦,因此查阅资料和阅读他人博客,总结出一套较为简洁的实现方案。
二、方案思路
1.后退不刷新肯定要使用keep-alive
2.前进刷新,有两种情况一种就是进入的页面从未打开过(不用考虑,肯定会刷新),一种是进入的页面已经被打开过,由于使用了keep-alive,如果不做任何处理,进入的页面肯定是不刷新的,还是上一次进入的状态。那么如果被打开过的页面被销毁,再次进入会不会刷新呢?答案是肯定的——会刷新。顺着这个思路,找到页面缓存信息的位置
this.$vnode.parent.componentInstance.cache,this.$vnode.parent.componentInstance.keys以及销毁实例的方法this.$destory()。
3.问题的关键销毁页面时机——执行后退时销毁页面。我这里通过给路由添加level来判断。
三、代码
1.路由文件 level属性标识层级,用于跳转时判断是前进还是后退。
export default [
{
name: 'index',
meta: {
level: 0, // 表示层级
},
path: '/',
component: (resolve)=>require(["@/pages/index.vue"], resolve)
},
{
name: 'about',
meta: {
level: 1, // 表示层级
},
path: '/about',
component: (resolve)=>require(["@/pages/about.vue"], resolve)
},
{
name: 'detail',
meta: {
level: 2, // 表示层级
},
path: '/detail',
component: (resolve)=>require(["@/pages/detail.vue"], resolve)
}
]
2.全局混入路由守卫beforeRouteLeave
export default {
data() {
return {}
},
methods: {
goBack() {
this.$router.back();
},
},
beforeRouteLeave(to,from,next) {
// 进入页面的层级小于离开页面的层级(后退)
if(to.meta.level < from.meta.level) {
let keys = this.$vnode.parent.componentInstance.keys;
let cache = this.$vnode.parent.componentInstance.cache;
let key = keys[keys.length-1];
// 组件被缓存
if(cache[key] !== null) {
delete cache[key]; // 删除缓存
keys.length--; // 删除key
}
// 销毁组件
this.$destroy();
}
next();
}
}
3.三个测试使用的文件, number为一个0~100的随机数可以标识页面是否刷新
index.vue
<template>
<div class="info">
我是首页我的计数为{{number}}
<router-link tag="button" to="/about">关于页</router-link>
</div>
</template>
<script>
export default {
name: "index",
data() {
return {
number: 0,
}
},
mounted() {
this.number = (Math.random()*100).toFixed(0);
}
}
</script>
<style scoped>
</style>
about.vue
<template>
<div class="info">
<button @click="goBack">返回</button>
我是关于页的计数为{{number}}
<router-link tag="button" to="/detail">详情页</router-link></div>
</template>
<script>
export default {
name: "about",
data() {
return {
number: 0,
}
},
mounted() {
this.number = (Math.random()*100).toFixed(0);
},
}
</script>
<style scoped>
</style>
detail.vue
<template>
<div class="info">
<button @click="goBack">返回</button>我是详情页的计数为{{number}}
</div>
</template>
<script>
export default {
name: 'detail',
data() {
return {
number: 0,
}
},
mounted() {
this.number = (Math.random()*100).toFixed(0);
}
}
</script>
<style scoped>
</style>
4.项目中src的目录结构
|--src
| |--assets // 静态资源
| |--components // 公共组件
| |--mixin // 全局混入
| | |--index.js
| |--pages // 页面信息
| | |--about.vue
| | |--detail.vue
| | |--index.vue
| |--router // 路由信息
| | |--index.js
| | |--routes.js
| |--App.vue
| |--main.js