文章目录
- 一、简介
- 基本用法
- 生命周期钩子
- 二、定义是否缓存组件
- 三、缓存组件
- 1. 通过 :include 属性实现
- vue2.x中
- vue3.x中
- 2. 通过 v-slot 功能实现
- 3. 通过 v-if 来实现
- 四、注意事项
一、简介
Vue Router 允许你缓存路由组件,这样在用户导航回之前的页面时,组件的状态会被保留而不是重新渲染。这可以通过使用 <keep-alive>
组件来实现。
<keep-alive>
是一个内置抽象组件,它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
它的主要作用是缓存不活动的组件实例,而不是销毁它们。
当组件在 <keep-alive>
包裹下被切换时,它的状态(包括数据、DOM 结构等)都会被保留,以便在下次重新显示时能够恢复之前的状态,而不是重新创建组件实例。
基本用法
<keep-alive>
<component :is="currentTabComponent"></component>
</keep-alive>
在上面的例子中,currentTabComponent
是一个动态组件,它的值会根据当前选中的标签页而变化。
使用 <keep-alive>
后,当切换标签页时,之前的组件实例会被缓存起来,而不是被销毁。
生命周期钩子
被 <keep-alive>
包裹的组件拥有两个特有的生命周期钩子:activated
和 deactivated
。
-
activated
:当组件被激活时调用,即在 keep-alive 缓存中组件再次可见时被调用。 -
deactivated
:当组件被停用时调用,即在 keep-alive 缓存中组件不可见时被调用。
这两个钩子可以帮助你更好地管理组件的状态,比如当组件重新被激活时,你可能需要重新获取数据或者更新视图。
二、定义是否缓存组件
根据路由的 meta
字段中的 keepAlive
属性来决定是否缓存组件。
如果 keepAlive 为 true,则组件会被缓存;否则,它会被缓存。
const routes = [
{
path: '/foo',
component: Foo,
meta: { keepAlive: true } // 这个组件会被缓存
},
{
path: '/bar',
component: Bar,
meta: { keepAlive: false } // 没有设置 meta.keepAlive 或其值为 false,则组件不会被缓存
}
// ... 其他路由配置
];
三、缓存组件
1. 通过 :include 属性实现
可利用keep-alive
的 include
或 exclude
属性(include 和 exclude 包含的name 是组件的name不是router name)来设置缓存:
include
值为字符串或者正则表达式匹配的组件name会被缓存。exclude
值为字符串或正则表达式匹配的组件name不会被缓存。
vue2.x中
通过 <keep-alive>
的 :include
属性来实现动态缓存组件
<template>
<div id="app">
<keep-alive :include="cachedViews">
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
cachedViews: [] // 存储需要缓存的组件名
};
},
watch: {
$route(to, from) {
// 过滤出需要缓存的组件,即 meta.keepAlive = true 的组件
const keepAliveComponent = to.matched.filter(record => {
return record.meta && record.meta.keepAlive;
});
if (keepAliveComponent.length) {
// 把需要缓存的组件的name放到cachedViews集合里
this.cachedViews = this.cachedViews.concat(keepAliveComponent.map(record => record.name));
} else {
const index = this.cachedViews.indexOf(to.name);
if (index > -1) {
this.cachedViews.splice(index, 1);
}
}
}
}
};
</script>
.
vue3.x中
在 Vue 3 中同样可以使用 <keep-alive>
的 :include
属性来实现动态缓存组件:
<template>
<div id="app">
<keep-alive :include="cachedViews">
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
import { ref, onMounted, watch, onUnmounted } from 'vue';
import { useRoute } from 'vue-router';
export default {
name: 'App',
setup() {
const cachedViews = ref([]);
const route = useRoute();
const updateCachedViews = () => {
const keepAliveComponent = route.matched.filter(record => {
return record.meta && record.meta.keepAlive;
});
cachedViews.value = keepAliveComponent.map(record => record.name);
};
onMounted(() => {
updateCachedViews();
});
watch(
route,
() => {
updateCachedViews();
},
{ immediate: false }
);
onUnmounted(() => {
// 清理操作,如果需要的话
});
return {
cachedViews
};
}
};
</script>
2. 通过 v-slot 功能实现
由于Vue 3 由于引入了组合式 API
和 v-slot
功能,有更简洁的方式来实现动态缓存:
<template>
<div id="app">
<router-view v-slot="{ Component }">
<keep-alive v-if="$route.meta && $route.meta.keepAlive">
<component :is="Component" />
</keep-alive>
<component v-else :is="Component" />
</router-view>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App'
});
</script>
使用<router-view>
的 v-slot
功能来访问当前路由组件的实例。
然后,我们检查这个组件的 meta.keepAlive
属性来决定是否将其包裹在 <keep-alive>
中。
3. 通过 v-if 来实现
在Vue2和Vue3中都可以使用 v-if="$route.meta.keepAlive"
来判断哪些组件需要缓存,简单粗暴
<template>
<div id="app">
<keep-alive v-if="$route.meta.keepAlive">
<router-view></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
</template>
<script>
import { defineComponent } from 'vue';
export default defineComponent({
name: 'App'
});
</script>
四、注意事项
-
虽然
<keep-alive>
可以提高性能,但也要避免过度使用,因为缓存的组件实例会占用内存。 -
当组件被
<keep-alive>
包裹时,它的created
和mounted
钩子只会在第一次渲染时调用,之后的切换不会再次触发这两个钩子。 -
如果需要强制刷新缓存的组件,可以通过改变 key 属性或者使用 ·include/exclude· 属性来动态控制哪些组件需要被缓存。