Vue中刷新当前页的几种方式及优劣分析

这个问题其实百度一下就有一堆解决方案,但是却很少有文章去分析他们各自的优势和劣势,而我这篇文章,也是在具体项目开发中,踩过一些坑后的心得和总结。

方案一

基本不会使用的方案,就是通过 location.reload() 或者 $router.go(0) 进行一次页面重新载入,效果等同于手动按 F5 刷新。

为什么说基本不用,因为弊端也很明显。首先体验不好,页面重新载入会出现大段时间的白屏;其次如果使用了 Vuex ,刷新可能会导致数据被清空。

方案二

准备一个空白页,页面里只做一件事,就是 $router.go(-1) ,需要刷新当前页的时候,只需跳转到该页面即可。

这个方案也会出现一小段白屏的时间,但问题不大,可以通过一些 loading 效果遮盖;其次因为是前进到一个空白页,再返回当前页,在 PC 端会出现一个小的 bug ,就是刷新一次之后,浏览器上的前进按钮会变成可点击,演示如下图:

方案三

网上能搜到最推荐的解决方案。就是通过 v-if 控制 <router-view> 的显示,如果要刷新页面,则将 <router-view> 销毁再重建一次即可。具体实现代码如下:

主要改造的就是 App.vue 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<template>
<div id="app">
<RouterView v-if="isRouterAlive" />
</div>
</template>

<script>
export default {
provide() {
return {
reload: this.reload
}
},
data() {
return {
isRouterAlive: true
}
},
methods: {
reload() {
this.isRouterAlive = false
this.$nextTick(() => (this.isRouterAlive = true))
}
}
}
</script>

通过 Vue 的 provide / inject ,将 App.vue 里的 reload() 方法注入到子页面里,这样在子页面里就可以通过这样的方式使用了。

1
2
3
4
5
6
7
8
9
10
<script>
export default {
inject: ['reload'],
methods: {
func() {
this.reload()
}
}
}
</script>

当然还可以更极致一点,就是直接在 App.vue 里监听路由的变化,如果当前路由和上一个路由的 name 属性一样,则可以认为是刷新页面操作,自动执行 reload() 方法。实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<template>
<div id="app">
<RouterView v-if="isRouterAlive" />
</div>
</template>

<script>
export default {
provide() {
return {
reload: this.reload
}
},
data() {
return {
isRouterAlive: true
}
},
watch: {
$route: 'routeChange'
},
methods: {
reload() {
this.isRouterAlive = false
this.$nextTick(() => (this.isRouterAlive = true))
},
routeChange(newVal, oldVal) {
if (newVal.name == oldVal.name) {
this.reload()
}
}
}
}
</script>

这样的好处在于,如果是在同一个路由,但不同参数间的跳转,能实现自动刷新页面。例如商城系统里最常见的,从一个商品详情页跳转到另一个商品详情页,这个时候,路由其实是没变化的,变化的只是 params 或者 query ,就不需要手动再去执行注入的 reload() 方法了。

这个方案看起来很完美,但有没有弊端呢?其实是有的,就是当项目在使用 keep-alive 做页面缓存的时候,会出现明显的问题。

因为一般做页面缓存都是通过 keep-alive 将 <router-view> 进行整页缓存,而刷新页面则是将 <router-view> 销毁并重建,所以一刷新,缓存就一并销毁了,所以在一些比较特殊的场景,还是有问题存在。

在遇到这样需要缓存页面的场景,方案二就体现出它的优势了。因为它是通过路由跳转刷新当前页面的,所以 <router-view> 始终都存在,就也能保证 keep-alive 的页面缓存不受到任何影响。

方案四

这种属于不太通用处理办法,就是在当前页面里手动再次获取相关数据,覆盖原有数据,实现刷新。这个方案的好处就是自由度更高,想重新获取哪些数据,就获取哪些数据,当然开发效率也会变低,因为无法形成通用的方案,到底要刷新哪部分数据,每个页面的业务逻辑都不一样。

总结

说白了,其实没有一种方案是完美的,还是得根据不同的场景,选择适合的解决方案。当然我个人还是更喜欢方案二和方案三结合使用,因为页面缓存使用的场景也是挺多的。