12.keep-alive

93 阅读2分钟

keep-alive是vue内置的组件,是用来缓存切换时不想被销毁的组件。一般情况下我们组件切换时时销毁组件的,切换回来时又重新加载,这种情况有时会浪费性能,而且不利于用户体验。

尝试一下

注意。这里使用v3,展示,我的vue-router版本是4.0+ 不能使用keep-alive包括router-link。v2可以直接写 app.vue

<template>
  <router-view v-slot="{ Component }">
    <keep-alive>
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>

a.vue

<template>
  这是a组件:<router-link to="/b">去b组件</router-link>
  <br />
  count:{{ count }} ---<button @click="count += 1">count+1</button>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(1);
</script>

b.vue 相同代码 不过a换成b 下面结果ab切换不会变化

image.png image.png

include,exclude

匹配首先检查组件自身的 name 选项,如果 name 选项不可用,则匹配它的局部注册名称 (父组件 components 选项的键值) 。匿名组件不能被匹配。include和exclude里面可以写字符串,正则,数组 app.vue include是能缓存的对象 exclude是不能缓存的 下面的include的 exclude同理

<template>
  <router-view v-slot="{ Component }">
    <keep-alive include="a"><!-- 字符串 -->
      <!-- <keep-alive :include="/a/">  正则-->
      <!-- <keep-alive :include="["a"]"> 数组 -->
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>

image.pngimage.png

activated,deactivated

组件被缓存的时候没有被销毁掉,所以下次进入的时候不会被重新创建。所以官方提供了activated,deactivated2个生命周期的钩子。一个是进入缓存时 一个是离开缓存时。我们就可以在这2个钩子里面执行我们自己的操作 a.vue

<template>
  这是a组件:<router-link to="/b">去b组件</router-link>
  <br />
  count:{{ count }} ---<button @click="count += 1">count+1</button>
</template>
<script setup>
import { ref, onActivated, onDeactivated } from 'vue';
const count = ref(1);
onActivated(() => {
  console.log('缓存开始了');
});
onDeactivated(() => {
  console.log('缓存结束了');
});
</script>

image.png

遇到的问题

你在组件初始化的时候去拿路由信息,或者其他信息去加载页面,但是缓存页面没有初始化这个阶段,你就不能执行这个操作,所以当你重新进入缓存页面的时候就不会加载信息。比如现在a组件里面由一个tabs,下面是2个组件,分别是新闻和运动,对应路由query参数type==news or sport。setup拿到type 然后对应加载。现在需求是缓存a组件,比如我在游览体育新闻,我在b组件跳回a组件的时候,需要展示体育新闻

<template>
  <router-view v-slot="{ Component }">
    <keep-alive include="a">
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>
<template>
  这是a组件:<router-link to="/b">去b组件</router-link>
  <br />
  <div
    class="tabs"
    @click="
      router.push({
        path: '/a',
        query: {
          type: 'news'
        }
      })
    "
    :class="router.currentRoute.value.query.type == 'news' ? 'active' : ''"
  >
    新闻
  </div>
  <div
    class="tabs"
    @click="
      router.push({
        path: '/a',
        query: {
          type: 'sport'
        }
      })
    "
    :class="router.currentRoute.value.query.type == 'sport' ? 'active' : ''"
  >
    体育
  </div>
  <div class="content" v-if="router.currentRoute.value.query.type == 'news'">
    新闻内容
  </div>
  <div class="content" v-if="router.currentRoute.value.query.type == 'sport'">
    体育内容
  </div>
</template>
<script setup>
import { ref, onActivated, onDeactivated } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const type = ref(router.currentRoute.value.query.type || 'news');
</script>

image.png 这时候你从b组件跳回a的时候,就没有信息展示

image.png

解决办法

记录页面选中参数,进入缓存时读取参数

<template>
  这是a组件:<router-link to="/b">去b组件</router-link>
  <br />
  <div
    class="tabs"
    @click="tabsClick('news')"
    :class="type == 'news' ? 'active' : ''"
  >
    新闻
  </div>
  <div
    class="tabs"
    @click="tabsClick('sport')"
    :class="type == 'sport' ? 'active' : ''"
  >
    体育
  </div>
  <div class="content" v-if="type == 'news'">新闻内容</div>
  <div class="content" v-if="type == 'sport'">体育内容</div>
</template>
<script setup>
import { ref, onActivated } from 'vue';
import { useRouter } from 'vue-router';
const router = useRouter();
const type = ref(router.currentRoute.value.query.type || 'news');
const tabsClick = (checked) => {
  type.value = checked;
  router.push({ path: '/a', query: { type: checked } });
};
onActivated(() => {
  router.push({ path: '/a', query: { type: type.value } });
});
</script>

同理 还有屏幕滚动高度这些也是一样的,在进入缓存时读取,优化用户体验