Skip to content

drinkeewu/vue-keep-alive-solution-demo

Repository files navigation

Vue keep-alive solution demo

项目启动

npm install
npm run serve

说明

在日常开发中, 经常会遇到这样的需求: 跳转到详情页面后, 再返回到列表页时需要恢复到跳转前的滚动位置或页码位置,以提高用户体验。在Vue项目中,我们可以是用keep-alive组件进行页面进行“缓存”。对于keep-alive是什么,这里就不再赘述,本文主要介绍多层(两层或以上)嵌套路由的情况下的实现方案。

基本使用方法

<template>
  <!-- ... -->
  <keep-alive>
    <router-view />
  </keep-alive>
</template>

参考链接: API keep-alive

需求场景

  • 现有页面:列表页(A)、详情页列表页(B)、详情页(C),其他页面(D),进入顺序:A > B > C
  • A跳转到B,B返回A:A保持状态
  • B跳转到其他页面(除了C的页面):销毁B的”缓存“状态
  • B跳转到C:C返回B,B保持状态
  • C跳到其他页面(除了B的页面),销毁A和B的”缓存“状态

实践方案

思路及步骤:

  1. vuex中定义全局缓存数组keepAliveComps
// 全局状态 store.js 
export default new Vuex.Store({
  state: {
    /** 全局缓存数组 */
    keepAliveComps: [],
  },
  mutations: {
    [types.ADD_KEEP_ALIVE_COMP](state, component) {
      !state.keepAliveComps.includes(component)
        && state.keepAliveComps.push(component);
    },
    [types.DELETE_KEEP_ALIVE_COMPS](state, component) {
      if (Array.isArray(component)) {
        state.keepAliveComps = state.keepAliveComps.filter(
          (name) => !component.includes(name),
        );
      }
    },
  },
});

2.把全局的缓存数组传给keep-alive组件的include属性

<!--App.vue-->
<template>
  <div id="app">
    <!--传入全局缓存数组给include-->
    <keep-alive :include="keepAliveComps">
      <router-view />
    </keep-alive>
  </div>
</template>

<script>
import { mapState } from 'vuex';
export default {
  name: 'App',
  computed: {
    ...mapState(['keepAliveComps']),
  },
  //...
};
</script>
  1. 在需要缓存的页面(组件)的路由对象中,约定metakeepAlive的值为true时,对该组件进行缓存;在路由钩子函数beforeEach中,把需要缓存的组件名添加到全局缓存数组keepAliveComps
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [
    {
      path: '/A',
      name: 'A',
      component: () => import('../views/A.vue'),
      meta: {
        keepAlive: true,
      },
    },
  ]
});
router.beforeEach((to, from, next) => {
  if (to.meta && to.meta.keepAlive) {
    store.commit(types.ADD_KEEP_ALIVE_COMP, to.name);
  }
  next();
});
  1. 在组件钩子beforeRouteLeave中,根据下一个页面的名称,判断是否需要取消自身组件或上级组件的缓存。
<script>
import * as types from '../store/types';

export default {
  name: 'C',
  beforeRouteLeave(to, from, next) {
    if (to.name !== 'B') {
      this.$store.commit(types.DELETE_KEEP_ALIVE_COMPS, ['A', 'B']);
    }
    next();
  },
};
</script>

C只有返回到它的”父级“路由 (B)时,A和B才需要继续被缓存。当C跳转到其他非”父级“路由后,再重新进入A或B,此时的A或B都是全新的组件。所以当进入的页面是非”父级“路由时,需要清除所有”父级“路由组件的缓存状态。

流程示意图: image

总结及注意事项

缓存不生效

keep-alive组件的include数组操作的对象是组件的名称,而不是路由的名称,因此我们需要在定义每一个组件时,显式声明name属性,否则你会发现缓存不起作用。而且,一个显式的name对Vue devtools有提示作用。建议把路由对象与对应组件的设置为统一名称

例如:

<script>
export default {
  name: 'C',
  //...
};
</script>

重新进入缓存的组件

如果要在每次进入被缓存的路由页面时重新获取最新数据,需要在activated钩子函数内进行操作。

参考链接:

API activated

About

Solution demo for Vue.js to use keep-alive

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published