Vue项目全局配置页面缓存之按需读取缓存的实现详解

 更新时间:2018年08月01日 09:20:20   作者:FrankCheung  
这篇文章主要给大家介绍了关于Vue项目全局配置页面缓存之实现按需读取缓存的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧

写在前面

一个web app的实际使用场景中,有一些情景的交互要求,是记录用户的浏览状态的。最常见的就是在列表页进入详情页之后,再返回到列表页,用户希望返回到进入详情页之前的状态继续操作。但是有些使用场景,用户又是希望能够获取最新的数据,例如同级列表页之间切换的时候。

如此,针对上述两种使用场景,需要实现按需读取页面缓存。由于SPA应用的路由逻辑也是在前端实现的,因此可以在前端对路由的逻辑进行设置以实现所需效果。

使用技术

  • Vue.js作为主要框架
  • Vue-router作为前端路由管理器
  • Vuex作为状态管理工具

总体思路

keep-alive判断当前组件是否读取缓存的节点,在整个生命周期里面非常靠后,在afterEach之后,基本在组件实例创建之前。(因此在此之前对当前组件是否读取缓存进行处理都是可行的,我选择在全局前置守卫进行处理)

而判断当前组件是否缓存的节点,则早于组件的beforeRouteLeave钩子。

基于上述逻辑,本方案解决的逻辑是,对当前打开的页面进行判断,动态生成需要keepAlive的组件数组配置,对有可能需要缓存的先行进行缓存,然后在每次路由切换的时候,再进行判断,按需读取页面缓存。

  1. 使用kepp-alive进行缓存,使用include属性对需要缓存的页面进行配置。
  2. 由于需要缓存的页面配置系动态生成,所以使用vuex储存该配置。
  3. 在路由元信息中写入两个配置,一是该路由是否需要缓存,二是从相关路由进入时才进行缓存的特定路由数组。
  4. 在beforeEach进行设置,每次进入路由之前,对进入的路由及其所有父级路由进行判断,若需要缓存且命中特定路由数组,则将相关路由添加至缓存配置文件中;若不符合,则将相关路由删除。(此步骤实现了路由切换时,需要则读取缓存,不需要则重新获取数据。)
  5. 使用全局mixin,进入相关组件之前,对当前路由进行判断,如果需要缓存的则将该路由添加至缓存配置中。(此步骤实现了缓存当前打开的需要缓存的页面。)

具体实现

1. 使用include属性控制路由缓存

此处需要注意的是,include匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值)。匿名组件不能被匹配。

但是vue-router的环境下,是没有局部注册名称的,只能为组件补全name属性。

因此,请务必给组件添加 name 选项,否则匿名组件将全部应用缓存。

<keep-alive :include="$store.state.cachedRouteNames">
 <router-view />
</keep-alive>

2. 添加全局路由缓存配置

// store/index.js

const store = new vuex.Store({
 state: {
 // 缓存的路由列表
 cachedRouteNames: [],
 },
 mutations: {
 UPDATE_CACHEDROUTENAMES(state,{ action, route }) {
  const methods = {
  'add': () => {
  state.cachedRouteNames.push(route)
  },
  'delete': () => {
  state.cachedRouteNames.splice(state.cachedRouteNames.findIndex((e) => { return e === route}),1)
  }
  }
  methods[action]()
 }
 }
})

3. 配置路由元信息,对需要缓存的路由进行配置

keepAlive表明路由需要被缓存,必须,否则不缓存

cacheWhenFromRoutes为数组,非必须,若为falsy值,则任何时候均缓存;若为空数组,则任何时候均不缓存

// router/index.js

{
 path: '/productslist',
 name: 'ProductsList',
 component: ProductsList,
 meta: {
 keepAlive: true,
 cacheWhenFromRoutes: ['ProductDetail'] // 此处配置的是路由的name
 }
},

4. 配置全局前置守卫,按需读取缓存

// routeControl.js

// 需要缓存的路由名称数组
const cachedRouteNames = store.state.cachedRouteNames;

// 定义添加缓存组件name函数,设置的是组件的name
const addRoutes = (route) => {
 const routeName = route.components.default.name
 if (routeName && cachedRouteNames.indexOf(routeName) === -1) {
 store.commit('UPDATE_CACHEDROUTENAMES', { action: 'add', route: routeName })
 }
}

// 定义删除缓存组件name函数,设置的是组件的name
const deleteRoutes = (route) => {
 const routeName = route.components.default.name
 if (routeName && cachedRouteNames.indexOf(routeName) !== -1) {
 store.commit('UPDATE_CACHEDROUTENAMES', { action: 'delete', route: routeName })
 }
}

router.beforeEach((to, from, next) => {
 
 // 处理缓存路由开始
 // 在读取缓存之前,先对该组件是否读取缓存进行处理
 to.matched.forEach((item, index) => {
 const routes = item.meta.cacheWhenFromRoutes;
 /**
  * 此处有几种情况
  * 1. 没有配置cacheWhenFromRoutes, 则一直缓存;
  * 2. 配置了cacheWhenFromRoutes,但是首次打开此web app,则from.name为空,此时应该将该页面组件的name添加到缓存配置文件中
  * 3. 配置了cacheWhenFromRoutes,from.name不为空,若命中cacheWhenFromRoutes,则添加该页面组件的name到缓存配置文件中,否则删除。
  *
  **/
 if (item.meta.keepAlive && (!routes || (routes && (!from.name || routes.indexOf(from.name) !== -1)))) {
  addRoutes(item)
 } else {
  deleteRoutes(item)
 }
 
 })
 // 处理缓存路由结束

 new Promise(( resolve, reject ) => {
 // ..other codes
 }).then( res => {
 if ( res ) {
  next(res)
 } else {
  next()
 }
 })
})

// 全局混入。此步骤的目的是在该组件被解析之后,若是属于需要缓存的组件,先将其添加到缓存配置中,进行缓存。

// 导航守卫的最后一个步骤就是调用 beforeRouteEnter 守卫中传给 next 的回调函数,此时整个组件已经被解析,DOM也已经更新。

Vue.mixin({
 beforeRouteEnter(to, from, next) {
 next(vm => {
  to.matched.forEach((item) => {
  const routeName = item.components.default.name
  if (to.meta.keepAlive && routeName && cachedRouteNames.indexOf(routeName) === -1) {
   store.commit('UPDATE_CACHEDROUTENAMES', { action: 'add', route: routeName })
  }
  })
 })
 },
})

写在最后

坑点

  • 此方案涉及两个name,一个是设置特定路由时,使用路由的name。另一个是动态生成缓存配置文件时,使用的是页面组件的name。
  • 务必给组件添加name属性,便于include属性的使用,也方便调试跟踪。如果组件缺少name属性,将会默认使用缓存。
  • 动态处理缓存配置时,一定要对to.matched进行遍历,否则嵌套路由的父级路由的缓存就无法生效,将导致子路由的缓存也无法生效。
  • 全局混入有一定危险性,慎用...

以上是实践过程中摸索出来的一种解决方案,我相信存在更加优雅高效的解决方式。如果你正好实践过相关方法,烦请指正,谢谢。

更多参考

github.com/vuejs/vue/i…

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • Vue 中文本内容超出规定行数后展开收起的处理的实现方法

    Vue 中文本内容超出规定行数后展开收起的处理的实现方法

    这篇文章主要介绍了Vue 中文本内容超出规定行数后展开收起的处理的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • LRU算法在Vue内置组件keep-alive中的使用

    LRU算法在Vue内置组件keep-alive中的使用

    LRU算法全称为least recently use 最近最少使用,核心思路是最近被访问的以后被访问的概率会变高,那么可以把之前没被访问的进行删除,维持一个稳定的最大容量值,从而不会导致内存溢出。
    2021-05-05
  • Vue手写横向轮播图的实例

    Vue手写横向轮播图的实例

    这篇文章主要介绍了Vue手写横向轮播图的实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • Vue.js实现watch属性的示例详解

    Vue.js实现watch属性的示例详解

    本文讨论了watch函数是如何利用副作用函数和options进行封装实现的,也通过调度函数去控制回调函数的立即执行和执行时机,还可以解决竞态问题,感兴趣的可以了解一下
    2022-04-04
  • element-ui组件table实现自定义筛选功能的示例代码

    element-ui组件table实现自定义筛选功能的示例代码

    这篇文章主要介绍了element-ui组件table实现自定义筛选功能的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)

    Vue中Table组件行内右键菜单实现方法(基于 vue + AntDesign)

    这篇文章主要介绍了Vue中Table组件行内右键菜单实现方法,该项目是基于 vue + AntDesign的,具体实例代码给大家介绍的非常详细 ,需要的朋友可以参考下
    2019-11-11
  • vue中用js如何实现循环可编辑表格

    vue中用js如何实现循环可编辑表格

    这篇文章主要介绍了vue中用js如何实现循环可编辑表格,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue eslint简要配置教程详解

    vue eslint简要配置教程详解

    这篇文章主要介绍了vue eslint简要配置,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-07-07
  • vue-cli3+echarts实现渐变色仪表盘组件封装

    vue-cli3+echarts实现渐变色仪表盘组件封装

    这篇文章主要为大家详细介绍了vue-cli3+echarts实现渐变色仪表盘组件封装,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-03-03
  • 详解Vue中如何进行状态持久化

    详解Vue中如何进行状态持久化

    在Vue应用中,通常需要将一些状态进行持久化,以便在用户关闭浏览器或刷新页面后,常见的方法就是LocalStorage和SessionStorage,所以本文就来讲讲这两种方法的具体实现吧
    2023-06-06

最新评论