Vue 全站缓存二:如何设计全站缓存

在前文Vue 全站缓存之 keep-alive : 动态移除缓存中,咱们实现了在路由离开时动态移除缓存这一功能,以此为基础,vue 全站使用缓存成为可能。javascript

本文长篇大论啰里啰嗦巴拉巴拉,请跳着读、反复读、随机读、躺着读……css

系列篇1:Vue 全站缓存之 keep-alive : 动态移除缓存html

本篇为系列篇2:Vue 全站缓存二:如何设计全站缓存前端

系列篇3:Vue 全站缓存之 vue-router-then :先后页数据传递vue

系列篇4:Vue 全站缓存之 vue-router-then :实现原理java

前言

从早期粗暴得将 css、js 资源设定浏览器本地缓存,到后来小图标合并成大图节省请求资源,还有动态请求304状态判断,而后 ajax 开启 web2.0 时代, pjax 大放光彩,到现在 vue.js 等前端框架的繁荣盛世,全部的这一系列发展,我认为,提速是一个核心驱动力。node

keep-alive

在 vue 里,支持 keep-alive 特性,经过 keep-alive ,再也不销毁旧组件为新组件让路,而是缓存起来以待未来复用,当复用缓存组件时,若是数据没有变化甚至能够直接原样恢复。连接web

keep-alive 和 vue-router

将 router-view 放置到 keep-alive 中,便可粗暴的实现全部路由页的缓存功能。ajax

<!-- App.vue -->
<keep-alive><router-view class="transit-view"></router-view></keep-alive>
复制代码

为何要使用缓存

最多见的一个场景是新建订单时选择地址,新建订单是一个路由页面,去选择用户现有的地址又是一个路由页面,因此理所固然的,咱们但愿用户选择完地址回到订单页面的时候,订单里的其余数据好比选择的优惠券啊收件日期啊都能继续保持。vue-router

在大量相似的场景里,不断的出现数据保留和复用的需求,因此 vuex 出现了,经过第三方的一个公共组件来保存和中转数据,这是一个解决方案,并且仍是主流的解决方案哦。

然而换个角度,若是订单页在选择地址的时候被缓存了,回到订单页后直接复用前面的订单组件,其余数据都保留此时只要更新下地址数据,让全部的代码逻辑都集中在订单组件之中,这样的开发体验是否是会更直观更友好?

这是见仁见智的思路,各有想法,很差说谁好谁坏,咱们就先继续讨论缓存组件的方案吧。

出现了一点小问题

若是全部的路由页都被缓存了,那么当你不想使用缓存的时候怎么办?好比又建了一个新订单,进入不一样文章的编辑组件,好比进入不一样的用户中心,缓存当然提了速,有时咱们也会不想要缓存功能,特别是一些表单场景,咱们既但愿填写一半进入下一页面时能保留填写的数据,咱们又但愿新进入的表单是一个全新的表单页。

鱼和熊掌能够兼得

咱们既但愿填写一半进入下一页面时能保留填写的数据,咱们又但愿新进入的表单是一个全新的表单页。

换句话说,回到上一个页面时使用缓存,进入下一个页面时不使用缓存

再换句话说,全部页面都用缓存,只在后退(回到上一页)时移除当前页缓存,这样下一次前进(进入当前页)时由于没有缓存就天然使用全新页面

也就是说,只要实现后退(回到上一页)时移除当前页缓存这个功能,就能够了。

在路由中定义位置

这是一种缓存复用的思路,为了实现后退(回到上一页)时移除当前页缓存,由于想要实现动态肯定用户的前进后退行为比较麻烦,因此,咱们有个傻瓜式的方案:预测使用场景约定各路由页面的层级关系。

好比,在 routes 定义里,咱们能够这么定义各路由页:

// 仅供参考,此处缺乏路由组件定义
// router/index.js
routes: [
        {   path: '/', redirect:'/yingshou', },
        {   path: '/yingshou',                meta:{rank:1.5,isShowFooter:true},          },
        {   path: '/contract_list',           meta:{rank:1.5,isShowFooter:true},          },
        {   path: '/customer',                meta:{rank:1.5,isShowFooter:true},          },
        {   path: '/wode',                    meta:{rank:1.5,isShowFooter:true},          },
        {   path: '/yingfu',                  meta:{rank:1.5,isShowFooter:true},          },
        {   path: '/yingfu/pact_list',        meta:{rank:2.5},                            },
        {   path: '/yingfu/pact_detail',      meta:{rank:3.5},                            },
        {   path: '/yingfu/expend_view',      meta:{rank:4.5},                            },
        {   path: '/yingfu/jizhichu',         meta:{rank:5.5},                            },
        {   path: '/yingfu/select_pact',      meta:{rank:6.5},                            },
        {   path: '/yingfu/jiyingfu',         meta:{rank:7.5},                            },
    ]
复制代码

核心的思路是,在定义路由时,在 meta 中定义一个 rank 字段来声明该路由的页面优先级, 好比 1.5 标识第 1 层如首页,2.5 表示第 2 层如商品列表页, 3.5标识第 3 层商品详情页,以此类推。

若是你们同在一层,也能够经过 1.4 和 1.5 这样小数位来约定前后层级。

总之,咱们指望的是,从第1层进入第2层是前进,从第3层回到第2层是后退。

在路由跳转里动态判断移除缓存

使用Vue.mixin的方法拦截了路由离开事件,并在该拦截方法中实现后退时销毁页面缓存

// main.js
Vue.mixin({
    beforeRouteLeave:function(to, from, next){
        if (from && from.meta.rank && to.meta.rank && from.meta.rank>to.meta.rank)
        {//此处判断是若是返回上一层,你能够根据本身的业务更改此处的判断逻辑,酌情决定是否摧毁本层缓存。
            if (this.$vnode && this.$vnode.data.keepAlive)
            {
                if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache)
                {
                    if (this.$vnode.componentOptions)
                    {
                        var key = this.$vnode.key == null
                                    ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
                                    : this.$vnode.key;
                        var cache = this.$vnode.parent.componentInstance.cache;
                        var keys  = this.$vnode.parent.componentInstance.keys;
                        if (cache[key])
                        {
                            if (keys.length) {
                                var index = keys.indexOf(key);
                                if (index > -1) {
                                    keys.splice(index, 1);
                                }
                            }
                            delete cache[key];
                        }
                    }
                }
            }
            this.$destroy();
        }
        next();
    },
});
复制代码

这样就好了吗

不行,这样只解决了动态移除缓存的状况,让用户既能够进入新页面,也能够回到旧页面。前者进新页面问题不大,后者回到旧页面这件事咱还没讨论过呢。

缓存是说用就用的吗

即便是路由页面复用了缓存,也只是复用了缓存的组件和数据,在实际场景中,从列表 A 进入详情 B 再进入列表 C ,请问 列表 C 和列表 A 是同一个路由页,但他们的数据会同样吗?应该同样吗?

因此就算是缓存了也要更新数据?

看起来,咱们获得了一个新结论,缓存页的数据也不可靠啊,摔,这日子快无法过了。

应该有办法的。

缓存的组件被复用时会触发 activated 事件,非缓存组件则会在建立时触发 created mounted 等一大堆事件,而同一个页面列表 A 进列表 B,由于 url 参数不一样,也会触发beforeRouteUpdate事件。连接1 连接2 连接3

看起来,咱们可以经过捕捉这些事件干点啥。

不对不对

第一直觉是,咱们在捕捉到页面载入的事件后去拉取数据更新页面。仔细一想,咱们上面罗里吧嗦废了老半天劲是为了进入缓存页面再也不看那 loading 条的啊。摔,怎么又绕回来了。

笨办法

这里提供一个笨办法,事件该捕捉咱仍是要捕捉,只是这是否去作拉取数据这个动做,咱能够有待商榷。

  • 在全部的路由页统一注册一个方法,就叫pageenter吧,无论从啥状况进来的,咱都去触发这个方法。
// list.vue
    data(){
        return {
            params        : null,
        }
    },
    methods:{
        pageenter:function(){
            this.params = {
                        'uuid'                 : this.$route.query.uuid   ,
                    };
        },
    }
复制代码
  • 若是直接 watch 这个 params ,这事仍是无法玩(请想下为何?),这里能够用一个笨办法,咱将它转化成字符串再 watch,捕捉到字符串变化再去从新拉取数据,若是字符串没有变化,则啥也不作。
// list.vue
    computed:{
        paramsToString(){
            return JSON.stringify(this.params);
        },
    },
    watch:{
        paramsToString:function(){
            this.loadContent();
        },
    },
    methods:{
        loadContent:function(){
            //此处拉取数据
            //this.$http.get(....)
        },
    }
复制代码
  • 在main.js里,能够用Vue.mixin拦截上文提到的三种事件,来触发 pageenter 方法。
//main.js
Vue.mixin({
    /*初始化组件时,触发pageenter方法*/
    mounted:function(){
       if (this.pageenter)
       {
           this.pageenter();
       }
    },
    // /*从其余组件返回激活当前组件时*/
    activated:function(){
       if (this.pageenter)
       {
           this.pageenter();
       }
    },
    /*在同一组件中,切换路由(参数变化)时*/
    beforeRouteUpdate:function(to, from, next){
        if (this.pageenter)
        {
            this.$nextTick(()=>{
                this.pageenter();
            });
        }
        next();
    },
});
复制代码

后语

至此,全站缓存的框架算是基本搭好了

吗?

请继续阅读-系列篇3:Vue 全站缓存之 vue-router-then :先后页数据传递

原文来自阿星的博客:wanyaxing.com/blog/201807…

相关文章
相关标签/搜索