实现方案--vue应用基于keep-alive页面缓存方案(web端)

零、先说重点

一年后重读此文章深感其中逻辑理解起来不够简单。还是决定先把关键点说清楚,后面的即使不看也能自由发挥。
可以实现的场景:
  • 锁屏页面:缓存上一次路由
  • 详情页面:缓存所属列表页面;其他页面跳转此页面均不缓存。
  • 主页面:均不缓存
1.利用keep-alive的include属性实现动态缓存
  • 以下为缓存的三种情况
// 1.不缓存
<keep-alive :include="[]"></keep-alive>
// 2.缓存所有页面
<keep-alive :include="/\.*/"></keep-alive>
// 3.缓存部分页面
<keep-alive :include="['pageA', pageB]"></keep-alive>
2.利用vue-router的路由守卫动态生成缓存规则
  • beforeEach:根据from,to生成。存储到vuex中。
let router = new Router({...});
router.beforeEach((to, from, next) => {
  setKeepAlive(from, to);
  setTimeout(_ => {
    next();
  }, 200);
});
function setKeepAlive(from, to) {
	// 1.你的逻辑
	// 2.存储到vuex中
}
  • 路由配置中存储生成依据
{
 path: 'A',
 name: 'A',
 meta: {
   title: '列表页1',
   逻辑中用到的变量: '', 
 },
 component: resolve => require(['../page/keepalive/A.vue'], resolve)
}
  • 注意要做from判断,首次进入页面和刷新时,均为null
重点已说完,以下为具体实现案例:

一、解决场景

现有页面:
  • 一层:登陆、主页、锁屏
  • 二层(主页下):列表页1、列表页2、详情页2、我的信息
达到效果
一层:
  • 主页<–>锁屏(缓存主页/主页中组件内容,不缓存锁屏)
  • 主页<–>登陆(不缓存)
二层:
  • 详情2 <–> 列表2(缓存列表2)
  • 列表1 --> 列表2(不缓存);列表1 --> 同层任意(缓存自身);
  • 我的信息 --> 同层任意(缓存其他同级,不缓存自身)

二、实现

思路

配置路由信息 --> 路由时确定缓存列表 --> keep-alive中include实时获取,达到动态效果

1.配置路由信息(router/index.js)
  • 页面分类一:缓存自身,有例外
{
  path: 'A',
  name: 'A',
  meta: {
    title: '列表页1',
    requireAuth: false,
    keepAlive_self: true, // 缓存自身
    keepAlive_excep: ['B'] // 当与B(列表页2)切换时不缓存
  },
  component: resolve => require(['../page/keepalive/A.vue'], resolve)
}
  • 不缓存自身,有例外
{
  path: 'B',
  name: 'B',
  meta: {
    title: '列表页2',
    requireAuth: false,
    keepAlive_self: false, // 不缓存自身
    keepAlive_excep: ['Bb'] // 当与Bb(详情页2)切换,缓存自身
  },
  component: resolve => require(['../page/keepalive/B.vue'], resolve)
}
  • 缓存其他所有同级页面
{
      path: 'C',
      name: 'C',
      meta: {
        title: '缓存组件c',
        requireAuth: false,
        keepAlive_other: true // 二级页面切换时,缓存
      },
      component: resolve => require(['../page/keepalive/C.vue'], resolve)
    },
    
  ]
}
  • 缓存所有页面
{
  path: '/lock',
  name: 'lock',
  meta: {
    title: '锁屏',
    requireAuth: false,
    g_keepAlive_other: true // 缓存所有页面
  },
  component: resolve => require(['../page/keepalive/lock.vue'], resolve)
}
2.配置时生成缓存列表(router/index.js)
import Vue from 'vue'
import Router from 'vue-router'
import store from '../store/store'

Vue.use(Router);
let router = new Router({...});
router.beforeEach((to, from, next) => {
  setKeepAlive(from, to);
  setTimeout(_ => {
    next();
  }, 200);
});
function setKeepAlive(from, to) {
  console.log('from,to:', from, to);

  // 设置状态可在vuex中简化代码,注意规则名称与组建name有关(并非路由中的name)
  if (!from.name) { // 如果没有上个页面信息(首次访问或刷新页面)
    console.log('如果没有上个页面信息(首次访问或刷新页面)');
    return null;
  } else if (from.meta.g_keepAlive_other || to.meta.g_keepAlive_other) { // 缓存所有一级以下路由:读取/储存
    console.log('缓存所有:读取/储存');
    store.commit('keepAlive', /\.*/); // 缓存所有二级
    store.commit('gKeepAlive', /\.*/); // 缓存所有一级
  } else if (from.meta.keepAlive_other || to.meta.keepAlive_other) { // 缓存其他页面:读取/储存
    console.log('缓存其他页面:读取/储存');
    store.commit('gKeepAlive', []); // 不缓存一级
    store.commit('keepAlive', /\.*/); // 缓存所有二级
    return null;
  } else {
    console.log('普通跳转:from与to分别只影响自身');
    // from:是否需要存储缓存
    let keppSelfF = from.meta.keepAlive_self || false;
    let excepListF = from.meta.keepAlive_excep || []; // 读取例外条件
    let isInF = excepListF.indexOf(to.name) > -1;
    let hasWrite = keppSelfF !== isInF; // 判断是否有例外

    // to:是否需要读取缓存
    let keppSelfT = to.meta.keepAlive_self || false;
    let excepListT = to.meta.keepAlive_excep || []; // 读取例外条件
    let isInT = excepListT.indexOf(from.name) > -1;
    let hasRead = keppSelfT !== isInT; // 判断是否有例外

    // 生成新缓存规则
    let keepAlive = [];
    if (hasWrite) {
      keepAlive.push(from.name);
    }
    if (hasRead) {
      keepAlive.push(to.name);
    }
    store.commit('gKeepAlive', []); // 不缓存一级一面
    store.commit('keepAlive', keepAlive); // 缓存所有二级页面
  }
}
3.vuex中state
  gKeepAlive: [], // 全局默认不缓存默认不缓存
  keepAlive: [] // 局部,默认不缓存
4.keep-alive组件动态读取
<!-- index.vue 一层 -->
    <keep-alive :include="$store.getters.gKeepAlive">-->
      <router-view/>
    </keep-alive>
<!-- main.vue 二层 -->  
    <keep-alive :include="$store.getters.keepAlive">
      <router-view/>
    </keep-alive>

5.缓存其他页面,但自身不缓存,离开前需要销毁自身缓存信息
// 防止缓存
  beforeRouteLeave(to, from ,next) {
    this.$destroy();// 销毁缓存
    next();
  }

其他

  • 存在问题
  1. 如果多层嵌套可能要多个vuex变量控制。
  • 尝试过方式
期间使用过切换的方式,弊端是已渲染的页面无法动态设置缓存。
而且from和to要分开判断,(存储与读取缓存要分开)
试图动态设置路由配置的meta信息,发现实时性不好,而且bug多。
<keep-alive>-->
  <router-view v-if="$store.keep"/>
</keep-alive>
<router-view v-if="!$store.keep"/>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值