记一次vue 的keep-alive踩坑之路

这个坑,从项目开始的时候就一直存在,在前期的时候还没有影响到正常的流程,加之项目比较紧,就一直没有花太多时间去管它。 可是在最近的业务中,这个问题已经影响到了正常的流程,所以这周一直在寻找这个问题的解决方案。在经历了各种论坛和各种贴子之后,找到了我目前能找到的最合适的解决方法,于是写下了这篇文章。

背景

用vue+cordova 做一个hybrid App,由于业务涉及的输入数据比较多,可能一个表单会包含多个子页面,这就要求在录入数据的时候,进入子页面之前需要将当前页的数据缓存,而在子页面返回的时候,子页面要销毁。也就是说,app正常前进的时候,页面全部缓,返回的时候之前的页面不需要刷新数据,直接读取缓存数据。
具体场景和这位仁兄一致: 另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新

为了找到一个合适的解决方案,我将这个场景进行了尽可能的简化,做成了一个DEMO,用来模拟这个场景。

Demo是用Vue-cli生成的,加上了简单的几个文件
项目结构如下图:


项目结构图

其中,child目录用来模拟子路由的,first/second是一级路由
具体路由文件如下:


router/index.js

最开始,什么都不处理,只要上页面上加上<router-link/> 是可以直接跳转的,当然也不会缓存任何组件。

给子路由加上缓存

我的最终目的给项目中所有的模块进行单独缓存,而一级页面不缓存。所以用child来模拟一个模块,first.vue 和 second.vue来模拟一级页面
每个模块(child)都有自己的入口,如child/index.vue,内容如下:


child/index.vue

这样可以将child下面所有的子路由进行缓存,可以用vue-devtool工具进行查看是否能够成功缓存


vue-devtool

可以看到,child下面的list以及detail组件已经缓存成功了。
到这里,已经实现了子路由的成功缓存。

但是这样会有一个问题:在页面返回的时候,所以被缓存的组件,会一直被缓存,再次进入页面的时候,组件并不会自动刷新,所以造成从list 点击不同的详情页的时候,进入的都是同一个页面。
在vue-devtool中看到的现象如下图:

缓存成功

当然,这种情况下也是有方法进行数据刷新的。因为所有被缓存的组件,再次进入的时候,会触发其生命周期的activated方法(https://cn.vuejs.org/v2/api/#keep-alive),可以在此进行强制数据刷新。
显然,这种方法不是我想要的。

在返回之前销毁当前实例

上面那种方法的问题在于:页面返回的时候,后面的组件(实例)还被缓存着,所以vue并不会重新去刷新它们。那么,如果在页面返回之前将自己销毁掉,vue也就找不到了,问题不就解决了么

正好,我项目用的ui框架是vonic https://github.com/wangdahoo/vonic/ ,在学习大神的源码的时候,发现了这样的一段代码,

vonic

这段代码的作用有两点:1、设置页面切换的动画(前进=》'forward',返回=>'back' );2、设置页面返回后的page position,也就是页面滚动的位置。
实现原理大致如下:
用sessionStorage来存储app打开过的路由,每当在路由跳转之前,先判断将要去的路由toRoute是不是在sessionStorage里面存在:如果存在,那么页面就是返回,将下一次路由切换的动画换成back,并改变sessionStorage中的history=false;如果不存在,那就是前进打开新的页面,同时将下一次路由切换的动画改成forward,同时改变sessionStorage中的history=true,并记录当前页的scrollTop。

其实vue-router本身的路由和浏览器的history对象一样,对应用程序来说,是不能直接操作的,这里作者用sessionStorage来模拟一个history,从而实现某些功能,这种方法是值得点赞的。

到这里,我们已经可以知道应用曾经打开过哪些页面,那我们在返回的时候是不是可以将某些页面销毁呢?答案是肯定的。

我们要做的是,在页面返回之前,也就是路由切换之前,要获取需要销毁的实例对象。
上图中有一个beforeEach,是vue-router提供的一个全局的钩子函数,它可以监听到每一次路由的切换,但却获取不到任何vue的实例对象。
在看了几遍vue-router的文档之后https://router.vuejs.org/zh-cn/advanced/navigation-guards.html ,我找到了一个组件内的钩子,也就是官方文档提到的导航守卫,如下图所示:

导航守卫

其中,我们要用到的是这个beforeRouteLeave,在将要离开组件对应路由的时候会触发这个钩子。而最重要的是,这个钩子可以获取到当前的组件实例this,所以我们可以在这个时候调用this.$destory()来销毁当前实例,就能完美解决上面提到的问题。
而这个钩子只能在组件内使用,也就意味着我每个需要缓存的组件都要调用这个钩子,难道每个组件里面都去写一遍这个钩子函数吗?

当然不用。

vue提供了全局的mixin方法,可以帮你在所有的实例里面加上这个钩子。

由于我的demo中没有用到vonic,所以我只能参照大神的源码,写了一段,具体如下:


main.js

这样,便可以实现,前进的时候缓存组件,返回的时候不刷新,并将最后一个页面销毁。

理论上,这个方案挺完美的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 本文首发于TalkingCoder,一个有逼格的程序员社区。转载请注明出处和作者。 写在前面 本文为系列文章,总共...
    Aresn阅读 9,448评论 0 42
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,125评论 0 6
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 4,989评论 0 29
  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 10,916评论 4 129
  • 坐在沙发一头,右腿蜷在左腿下,胳膊支在扶手上,低矮的木质扶手还垫了个抱枕,靠上去很舒服。已经快下午三点了,今天你还...
    Lnrsyao阅读 210评论 0 0