潇潇洒洒写一个KeepAlive动态缓存组件

4,947 阅读3分钟

你们好呀,我是wangly。一名不怎么摸鱼的前端小倒霉蛋。

这篇文章主要写了一下大部分Admin系统中常见的动态缓存组件,说通俗一点就是TagsBar组件。可以看下@panjiachen大佬Admin项目。集成在一完整项目中的组件或多或少会依赖一些其他的东西,这一次就开始从零实现这个功能吧。源码在底部,每一步都附待思路图哦。

效果图
效果图

开始

画了一张很水的图,其实整个过程很简单,进入页面路由后,判断当前路由是否是在白名单中,像登录页面,404等页面是不需要被缓存的。只有后台管理系统的页面需要缓存,那么就将当前路由信息缓存到Vuex的缓存区。在通过缓存区的内容生成keep-aliveinclude的匹配条件。同时根据缓存区的内容生成标签。那么下面就开始吧

流程图
流程图
效果演示图
效果演示图

进入路由后

为什么不在进入页面前,我的考虑是,只有真正到达了路由了才算是进入页面。所以说,在路由的after钩子中进行操作。

router.afterEach((to, from) => {
  // ... 判断是否在白名单
  // ... 添加缓存区
})

是否在白名单

验证是否是一些在白名单的路由。像基本的登陆页面,404时不要进行缓存的。因此需要过滤掉它。其次在通过一个Mutations方法changeCacheKeepMap修改和添加缓存的路由组件。

router.afterEach((to, from) => {
  if (!whitePath.includes(to.path)) {
    Store.commit('changeCacheKeepMap', to)
  }
})

添加到缓存区

vuex中的changeCacheKeepMap主要是对statecacheKeepMapMap数据进行一个操作。众所周知,Map是有序的。值是无重复的。在这里非常适合作为主要数据结构。在这里Mapkey设置为路由的名称。内容就是路由信息。需要注意的是,Vue对于Map的支持较差,所以只能直接重新覆盖原数据才能进行响应式。这里是一个坑点。

路由名称 = 组件名称,这一步很重要。因为它是作为KeepAlive组件缓存的依据。没有这个依据,就上不了车。

/**
 * 添加缓存组件信息
 * @param {RouteConfig} route
 */
changeCacheKeepMap(state, route) {
  const swapMap = new Map(state.cacheKeepMap)
  swapMap.set(route.name, route)
  state.cacheKeepMap = swapMap
}
Vuex数据
Vuex数据

缓存router-view

通过keep-aliveinclude来进行组件缓存凭证。需要在缓存的页面中标明name属性。 filterIncludeComponentName计算属性主要是将Map存放的key全部汇聚成为一个数组。作为include的条件。

// DOM

<keep-alive :include="filterIncludeComponentName">
  <router-view/>
</keep-alive>

// filterIncludeComponentName计算属性
filterIncludeComponentName () {
  const componentNames = []
  for (const key of this.cacheKeepMap.keys()) {
    componentNames.push(key)
  }
  return componentNames
}
缓存组件
缓存组件

include 使该标签作用于所有name属性的值跟此标签 include 的属性值一致的vue页面

顶部标签生成

这里就简单的多了,通过v-for遍历出Mapkeyvalue,非常的简单。然后设置标题,给route-link绑定to。通过当前路由的namelabel进行当前路由的判断。这里逻辑非常简单。

<router-link
  class="header-menu__item"
  :to="value.path"
  :class="$route.name === label && 'is-active'"
  tag="li"
  v-for="[label, value] in cacheKeepMap"
  :key="label"
>
  <a-badge :status="$route.name === label ? 'processing' : 'default'" />
  <span class="tag-text">{{value.meta.title}}</span>
  <a-icon type="close" @click.stop="onCloseTag(label)" class="close-btn" />
</router-link>

扩展...

还有需要扩展的功能对于大家来说,是可以扩展的。比如清除缓存区,缓存区更新啥的。都是根据自己的需求来定义。如果你看完了文章,那么这些都难不住你。正所谓,知其一而知其三,方为学习。根据自己的思考,去扩展自己想要的功能,本身就是一种进步。

总结

本篇文章属于简单的技术分享文,如果对你有用,不妨给我点个赞吧。最近一直都是在看其他的资料,和准备编写一本小册。一些项目都懒散了。每周几篇文章总结还是有的。以后会多多更新的。

下面附上源码地址给大家参考:

源码项目:链接

EleganceUI 求星星:链接