如何在vue中使用keepalive,以及如何移除keepalive

标题什么是keepalive?

在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。
也就是说,keepalive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存

基本用法

<keep-alive>
    <component />  //你的组件
</keep-alive>

被keepalive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数
但是有时候是希望我们缓存的组件可以能够再次进行渲染,这时Vue为我们解决了这个问题
被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated

activated 当 keepalive 包含的组件再次渲染的时候触发
deactivated 当 keepalive 包含的组件销毁的时候触发

keepalive是一个抽象的组件,缓存的组件不会被mounted,为此提供activated和deactivated钩子函数
在2.1.0 版本后keep-alive新加入了两个属性: include(包含的组件缓存生效) 与 exclude(排除的组件不缓存,优先级大于include) 。

参数理解
keepalive可以接收3个属性做为参数进行匹配对应的组件进行缓存:

  • include包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)

  • exclude排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)

  • max缓存组件的最大值(类型为字符或者数字,可以控制缓存组件的个数)

注:当使用正则表达式或者数组时,一定要使用v-bind
代码示例:

<!-- 逗号分隔字符串 -->
<keep-alive include="a,b">
  <component :is="view"></component>
</keep-alive>

<!-- 正则表达式 (使用 `v-bind`) -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- 数组 (使用 `v-bind`) -->
<keep-alive :include="['a', 'b']">
  <component :is="view"></component>
</keep-alive>
// 只缓存组件name为a或者b的组件
<keep-alive include="a,b"> 
  <component />
</keep-alive>

// 组件name为c的组件不缓存(可以保留它的状态或避免重新渲染)

<keep-alive exclude="c"> 
  <component />
</keep-alive>

// 如果同时使用include,exclude,那么exclude优先于include, 下面的例子只缓存a组件

<keep-alive include="a,b" exclude="b"> 
  <component />
</keep-alive>
// 如果缓存的组件超过了max设定的值5,那么将删除第一个缓存的组件
<keep-alive exclude="c" max="5"> 
  <component />
</keep-alive>


!!<keep-alive> 不会在函数式组件中正常工作,因为它们没有缓存实例。

配合router使用

router-view也是一个组件,如果直接被包在keepalive里面,那么所有路径匹配到的视图组件都会被缓存,如下:

<keep-alive>
    <router-view>
        <!-- 所有路径匹配到的视图组件都会被缓存! -->
    </router-view>
</keep-alive>

如果只想要router-view里面的某个组件被缓存,怎么办?

  • 使用 include/exclude
  • 使用 meta 属性
    1.使用 include (exclude例子类似)
//只有路径匹配到的 name 为 a 组件会被缓存
<keep-alive include="a">
    <router-view></router-view>
</keep-alive>

2.使用 meta 属性

// routes 配置
export default [
  {
    path: '/',
    name: 'home',
    component: Home,
    meta: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/profile',
    name: 'profile',
    component: Profile,
    meta: {
      keepAlive: false // 不需要被缓存
    }
  }
]
<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件,比如 Home! -->
    </router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不会被缓存的视图组件,比如 Profile! -->
</router-view>

!!这里需要注意的是,如果你是通过这种设置meta的方式创建keepAlive的话,keepAlive组件一旦被创建,就不会被销毁了,如果你想通过改变meta的方式销毁keepAlive,这样做是不可行的!!!网上很多教程叫你把meta的keepAlive设置为false,他们到底有没有实验过啊,真坑!那么如果你设置了keepAlive之后,又有某种特殊情况想销毁的话,那要怎么做呢?这里建议通过vuex配合设置include来决定页面是否需要keepAlive,下面是具体实现例子。

比如,你有这个需求:
首页是A页面
B页面跳转到A,A页面需要缓存
C页面跳转到A,A页面不需要被缓存

在你需要的设置缓存的页面:

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

<script>
  computed: {
    ...mapGetters([
      'keepAlivePage'
    ])
  }
</script>

在vuex中(我这里把vuex按照模块划分了,如果不是用Moudules这种的话自行转义哈)

getters中

const getters = {
  keepAlivePage: state => state.settings.keepAlivePage // 获取需要缓存的页面
}
export default getters

state中

const state = {
  keepAlivePage: [] // 需要缓存的页面,如果说你一开始就要缓存,那么你可以在这里设置初始值,如果你不需一开始就设置缓存,那么设置为空,再通过某种条件通过mutations或者actions改变keepAlivePage
}

如果说我要增加一个页面缓存,那么我在我需要增加的代码逻辑上增加下面一行代码


    doSomeThing() {
      doSomeThing(1001)
        .then(res => {
          if (res.code === 200 && res.data.length) {
         	doSomeThing....
            // 把页面keepAlive缓存
            this.$store.dispatch('settings/addKeepAlivePage', 'Home') //'Home'就是你要增加页面缓存的名称。
          }
        })

然后再vuex的actions中

const actions = {
  addKeepAlivePage ({ commit }, name) {
    commit('ADD_KEEP_ALVE', name)
  }
}

vuex的mutations中

const mutations = {
 ADD_KEEP_ALVE: (state, name) => {
    state.keepAlivePage = state.keepAlivePage.concat(name)
  }
}

这样子‘Home’组件就会被添加到缓存之中

注意!!这里要特别注意页面组价的名字要和router设置页面的名字要一一对应,不然的话接下来的需求就会实现不了!!
如何在vue中使用keepalive,以及如何移除keepalive_第1张图片
如何在vue中使用keepalive,以及如何移除keepalive_第2张图片
接下来回到刚刚那个需求,
B页面跳转到A,A页面需要缓存
C页面跳转到A,A页面不需要被缓存

思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置修改vuex中的keepAlivePage数组,把router的Name名字和keepAlivePage数组对比,如果你要缓存直接添加上就好了,如果不需要就对比里面是否有这个Name,有的话就删除就好了

例如:我在404页面跳转到home界面的话需要清除keepAlive,那么我就可以在beforeRouteLeave这样设置

 methods: {
    goTo () {
      this.$router.go(-1)
    }
  },
  beforeRouteLeave (to, from, next) {
    console.log(to)
    this.$store.dispatch('settings/changeKeepAlive', to.name)
    next()
  }
}

vuex的actions中

 changeKeepAlive ({ commit }, name) {
    commit('CHANGE_KEEP_ALIVE', name)
  },

vuex的mutations中

  CHANGE_KEEP_ALIVE: (state, name) => {
    const keepAlivePage = state.keepAlivePage
    const index = keepAlivePage.indexOf(name)
    if (index > -1) {
      keepAlivePage.splice(index, 1)
    }
  }

这样子我就把keepAlivePage数组中的‘Home’删掉了,如果你要新增keepAlie页面的话,就用刚刚这个方法就好了

 this.$store.dispatch('settings/addKeepAlivePage', 'Home')

OK,现在需求完美解决,有问题可以留言提问

防坑指南
1.keep-alive 先匹配被包含组件的 name 字段,如果 name 不可用,则匹配当前组件 components 配置中的注册名称。
2.keep-alive 不会在函数式组件中正常工作,因为它们没有缓存实例。
3.当匹配条件同时在 include 与 exclude 存在时,以 exclude 优先级最高(当前vue 2.4.2 version)。比如:包含于排除同时匹配到了组件A,那组件A不会被缓存。
4.包含在 keep-alive 中,但符合 exclude ,不会调用activated和 deactivated。

你可能感兴趣的:(vue)