keep-alive动态缓存实现

1,792 阅读3分钟

keep-alive动态缓存实现

💡 前言:vue中的keep-alive(保活)是我们常用的一个内置组件,本文讲的是如何利用状态管理器和路由配合达到一个动态缓存的效果

文章最后有demo

keep-alive是vue内置的一个组件,而这个组件的作用就是能够缓存不活动的组件,我们能够知道,一般情况下,组件进行切换的时候,默认会进行销毁,如果有需求,某个组件切换后不进行销毁,而是保存之前的状态,那么就可以利用keep-alive来实现

场景需求:

  1. 直接使用keep-alive,导致所有页面都被缓存,与需求不符合
  2. 只通过设置include缓存部分组件,并非所有被缓存的组件都是每次被缓存,会根据不同的情况下缓存(比如:商品列表页面进入了某个商品详情,从商品详情返回到商品列表页面的时候,商品列表是不需要刷新的,但是如果从商品列表页去了个人中心,从个人中心返回到商品列表页,商品列表需要刷新)
  3. 真的需要实现的情况

首页->列表页->详情页

  • 首页:不管从哪个页面进入,都需要被缓存
  • 列表页:从首页进入到列表页,列表页是不需要被缓存的,从详情页进入列表页(返回)是需要被缓存的
  • 详情页:不需要被缓存

image.png

分析

  • 一个页面需不需要被保活,是什么时候决定的?

答: 在进入下一个页面之前

  • 避免所有页面被缓存?

答: keep-alive组件如果设置了 include,就只有和include 匹配的组件会被缓存

  • 怎么管理include的数据?

答: 存在vuex中,配置好路由信息,通过全局路由守卫去管理

第一步:App.vue

组件是否被缓存,取决于keep-alive中的include是否包含了该组件的name值(如果不加include,默认缓存所有组件)

// App.vue
<keep-alive :include="include">
	<router-view />
</keep-alive>

export default {
  name: 'App',
  computed: {
    vuexKeepAlivePages() {
      console.log('保活页面', this.$store.state.keepAlive.VUEX_KEEP_ALIVE_PAGES)
      return this.$store.state.keepAlive.VUEX_KEEP_ALIVE_PAGES
    }
  }
}

第二步:store

export const KEEP_ALIVE_PAGES = 'VUEX_KEEP_ALIVE_PAGES'
export default {
  state: {
    [KEEP_ALIVE_PAGES]: []   // 被保活的页面数组: [name1, name2]
  },
  mutations: {
    // 设置保活数组
    [KEEP_ALIVE_PAGES]: (state, params) => {
      state[KEEP_ALIVE_PAGES] = params
    },
    // 添加页面到保活数组
    addKeepAlive: (state, params) => {
      state[KEEP_ALIVE_PAGES] = [...new Set([...state[KEEP_ALIVE_PAGES], params])]
    },
    // 从保活数组里面删除指定页面
    removeKeepAlive: (state, params) => {
      if (state[KEEP_ALIVE_PAGES].includes(params)) {
        state[KEEP_ALIVE_PAGES] = state[KEEP_ALIVE_PAGES].filter((i) => i !== params)
      }
    }
  }
}

第三步: 路由配置

const router = new VueRouter({
  routes: [
    {
      path: '/',
      name: 'home',
      component: home,
      meta: { title: '首页', toKeep: '*' }
    },
    {
      path: '/list',
      name: 'list',
      component: list,
      meta: { title: '列表页', toKeep: ['detail'] }
    },
    {
      path: '/detail',
      name: 'detail',
      component: detail,
      meta: { title: '详情页' }
    }
  ]
})
// router 全局前置守卫
router.beforeEach((to, form, next) => {
  // 决定当前页面是否需要被保活
  if (form.meta.toKeep) {
    if (form.meta.toKeep === '*' || form.meta.toKeep.includes(to.name)) {
      store.commit('addKeepAlive', form.name)
      setTimeout(() => {
        next()
      })
      return
    }
  }
  store.commit('removeKeepAlive', form.name)
  next()
})

第四步:页面(组件)配置name值

需要在页面中配置name属性,否则会不生效

image.png

其他:

keep-alive不生效?

答:检查store是否已经存好了对应的name值,页面是否有配置name属性(第四步)

根据路由做的动态缓存的话,那在做完页面某个交互后需要清除缓存怎么处理?

答:可以手动触发store中的commit去增删改当前被缓存的页面

最后

还是老样子,还是把一份可执行的demo代码献上 github地址