vue单页应用前进刷新后退使用缓存的实现

您所在的位置:网站首页 vue路由后退刷新 vue单页应用前进刷新后退使用缓存的实现

vue单页应用前进刷新后退使用缓存的实现

2024-01-31 16:40| 来源: 网络整理| 查看: 265

目录

前言

问题场景

一、页面A->页面B->页面C

二、页面A->页面B->页面C->页面B

解决方案

(1) keep-alive时限前进刷新后退使用缓存

(2)结合vuex实现前进刷新后退使用缓存

注:

前言

vue-cli创建的创建结合keep-alive可以实现页面缓存的效果。但是,在实际的使用过程中,发现后退返回使用缓存,前进进入也是使用的缓存,页面不刷新。这对实际的应用来说不是太方便。在网上断断续续查了有不少人说的解决方案,但是都没有一种很终极很理想的解决方案。这篇博文结合我实际项目中的应用场景,分享下vue项目单页应用的关于缓存的使用。

问题场景 一、页面A->页面B->页面C

操作要求:

只有下一页前进操作,和返回上一页操作。不存在提交跳转的使用场景。那么要求无论页面是否设置了缓存,都要求前进时重新刷新,后退时使用缓存。项目中可能的应用场景如下:

A也是入口首页,B是列表,C是详情。C返回B还是原来的列表,但是B页面提供的有下拉刷新的功能。

二、页面A->页面B->页面C->页面B

操作要求:

A页面是入口页面,B页面是列表,C页面是详情。

在详情C页面,可能直接点击返回按钮返回到页面B,也可能点击提交按钮进行提交操作,还是返回到页面B,但是要求页面B进行刷新。也就是说,具备可能缓存要求的页面再次进入的时候有三种情况,即:前进进入一定重新刷新,“返回”(当前页面的上个页面就是点击按钮要进入的页面)进入的页面分两种情况,一种是刷新,一种是使用缓存。

解决方案

上面两种不同的应用场景,有不同的解决方案,使用的技术也不尽相同。但是都要结合keep-alive。其中第二种应用场景必须结合vuex,但是第一种简单场景则单单使用keep-alive就能实现。

(1) keep-alive时限前进刷新后退使用缓存

单单使用keep-alive实现场景一的方案需要借助meta.keepAlive属性来完成。代码如下:

在root.vue对router-vier进行如下调整:

简单说,就是通过给组件设置meta.keepAlive属性来显示缓存组件,还是重新刷新显示组件。我看到有些网页写到这一步,然后在router的index.js中给路由配置meta的默认值来完成页面缓存。这种方式只能在任何情况下第二次进入需要缓存的页面都不会刷新,即从A->B除了第一次会刷新外,后面都是走的缓存,这名下不符合需求。

后来又看到有网友说声明一个全局的beforeEach,维护一个路由列表,通过判断to.name是否是路由列表中最后一个路由判断是后退还是前进,进而设置页面是否缓存。我尝试了他的代码和方法,发现有些场景还是不能满足,例如第一次返回的时候,B页面还是会刷新,因为从A首次进入B的时候,B的meta.keepAlive=false,只有在从C返回的时候才设置成了true,此时从B进入C再返回B,B是缓存页面。但是再返回A从新走,又回走前面的流程,也就是说对于B页面始终又一次多余的刷新。但是他这种思路是可行的,我再他的基础上,进行了优化,除了维护一个路由列表外,我还要维护一个需要缓存的组件列表。代码如下:

var routerList = []; var keepAlived = ['dispatchIndex', 'serviceIndex', 'manageIndex']; router.beforeEach((to, from, next) => { var li = routerList.length; if (li > 0 && routerList[li - 1] == to.name) { // 后退 routerList.splice(routerList.length - 1, 1) if (keepAlived.indexOf(from.name) > -1) { from.meta.keepAlive = true; } } else { // 前进 if (!ctool.strIsEmpty(from.name)) { routerList.push(from.name); if (keepAlived.indexOf(to.name) > -1) { if (to.meta.keepAlive) { to.meta.keepAlive = false; } else { to.meta.keepAlive = true; } } if (keepAlived.indexOf(from.name) > -1) { from.meta.keepAlive = true; } } else { console.log("-------------"); } } next() })

整体思路还是一样,但是对代码进行了调整和优化,确保不会出现多余刷新的情况。

注:关于这种方式,需要说明的是,缓存的页面除非你在页面内部手动刷新,否则缓存不会自己刷新。也就说你给组件的meta.keepAlived设置true或者false,只是不过是修改其在那个router-view里渲染展示而已,而对于已经缓存过的组件,如果又让其显示缓存,那么还是显示的原来的缓存页面。

这种情况就造成场景二里提交返回时候列表的问题,列表即便刷新了,但是如果你又想使用缓存的话,还是原来第一次进入的缓存页面。这是这种解决方案自身决定的,也是keep-alive的特性决定的。

(2)结合vuex实现前进刷新后退使用缓存

根据场景二的情况,使用keep-alive的include和exclued属性结合vuex动态完成改变那些组件需要刷新,那些组件使用缓存。

首先,修改root.vue组件,代码如下:  

在root.vue的计算属性中,代码如下:

computed:{ includedComponents(){ return this.$store.state.includedComponents; }, excludedComponents(){ return this.$store.state.excludedComponents; } }

可以看到,哪些组件需要缓存,那些不需要缓存是通过vuex来动态存储的。

完成以上代码之后,同样的还是需要在main.js中进行全局路由守卫的编写,代码如下:

var routerList = []; router.beforeEach((to,from,next)=>{ var li = routerList.length; console.log(store.state.includedComponents); if(li > 0 && routerList[li - 1] == to.name){ /* 如果发现to.name等于list中当前最后一个,则说明是返回操作。 返回操作的时候,第一步是从list中清掉第一个路由对象。 第二步是判断一下当前的from.name是不是在缓存属性中,在的话,就从里面拿掉,因为下一次进入的时候, 要重新刷新。 */ routerList.splice(routerList.length - 1, 1); if(store.state.includedComponents.indexOf(from.name)>-1){ console.log('rm',from.name); store.commit('removeInclude',from.name); store.commit('addToExclude',from.name); } }else{ if (!ctool.strIsEmpty(from.name)) { routerList.push(from.name); if (store.state.excludedComponents.indexOf(to.name) > -1) { console.log('ad',to.name); store.commit('removeExclude', to.name); store.commit('addToInclude', to.name); } } } next(); });

这里可以看到,操作的逻辑其实也还是借助维护的路由列表来判断是前进还是后退。但是单单是这样,还不能解决问题,因为我们还要根据实际的业务场景来动态改变那些页面需要缓存,那些不需要缓存。在vuex的store.js中代码如下:

import Vue from 'vue' import vuex from 'vuex' Vue.use(vuex); const state = { includedComponents:['dispatchIndex', 'serviceIndex', 'manageIndex'], excludedComponents:[] } const mutations = { removeInclude(state,str){ state.includedComponents.splice(state.includedComponents.indexOf(str),1); }, addToInclude(state,str){ state.includedComponents.push(str); }, removeExclude(state,str){ state.excludedComponents.splice(state.excludedComponents.indexOf(str),1); }, addToExclude(state,str){ state.excludedComponents.push(str); } } var store = new vuex.Store({ state:state, mutations:mutations }) export default store;

很多时候并不是说所有页面都需要缓存的,所以需要缓存的页面还是需要提前设置在includedComponents数组中。然后我在utils.js中进行公共方法的封装,代码如下所示:

clearCache:function(router_name){ store.commit('removeInclude',router_name); store.commit('addToExclude',router_name); }

这个方法用来将页面缓存清除。

至此所有需要的代码都已完成。

按照场景二中的情况,在页面C中,如果我是正常的返回,那么直接使用this.$router.go(-1);

如果我在C页面中,点击提交按钮回到B页面,但是需要B页面需要刷新,则点击提交按钮的代码如下写:

ctool.clearCache('B');//ctool挂载在windows上全局对象 this.$router.go(-1);

这样返回到B页面,B页面就会重新刷新。

注:

在实际的开发中,还发现一个很好玩的现象。有一个组件C,设置其进行缓存,但是发现缓存失败,每次正常返回的时候还是会重新刷新页面,通过查看到发现,组件C的获取数据并刷新的操作是在组件的beforRouterEnter钩子函数中通过vm=>fun方式来调用的。后来写到create中,就正常了。

这就说明,路由钩子函数的执行和组件是否缓存没有关系,他都会按照正常的流程进行执行。

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3