目录
一、动态组件标签
<component :is="tabs[currentTab]"></component>
有些场景会需要在两个或者更多个组件间来回切换,比如 Tab 界面。
下面的例子是通过 Vue 的 <component>
元素和特殊的 is属性
实现的。
<component :is="tabs[currentTab]"></component>
被传给 :is
的值可以是以下几种:
- 被注册的组件名
- 导入的组件对象
也可以使用 is属性
来创建一般的 HTML 元素。
二、在动态组件上使用keep-alive
1、基本使用
<KeepAlive>
是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。
<keep-alive>
同样也是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在组件的父组件链中。
当使用 <component :is="...">
来在多个组件间作切换时,被切换掉的组件会被卸载。
重新创建动态组件的行为通常是非常有用的,但是在有些案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。
我们可以通过 <KeepAlive> 组件强制被切换掉的组件仍然保持“存活”的状态。
使用 <keep-alive>
元素将其动态组件包裹起来。
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
注意:这个
<keep-alive>
要求被切换到的组件都有自己的名字,不论是通过组件的name
选项还是局部/全局注册。
tab切换过程缓存的效果如下代码实例:
<!DOCTYPE html>
<html>
<head>
<title>Vue Component Blog Post Example</title>
<script src="https://unpkg.com/vue@2"></script>
<link rel="stylesheet" type="text/css" href="/style.css" />
</head>
<body>
<div id="dynamic-component-demo">
<button
v-for="tab in tabs"
v-bind:key="tab"
v-bind:class="['tab-button', { active: currentTab === tab }]"
v-on:click="currentTab = tab"
>
{{ tab }}
</button>
<keep-alive>
<component v-bind:is="currentTabComponent" class="tab"></component>
</keep-alive>
</div>
<script>
Vue.component("tab-posts", {
data: function() {
return {
posts: [
{
id: 1,
title: "Cat Ipsum",
content:
"<p>Dont wait for the storm to pass, dance in the rain kick up litter decide to want nothing to do with my owner today demand to be let outside at once, and expect owner to wait for me as i think about it cat cat moo moo lick ears lick paws so make meme, make cute face but lick the other cats. Kitty poochy chase imaginary bugs, but stand in front of the computer screen. Sweet beast cat dog hate mouse eat string barf pillow no baths hate everything stare at guinea pigs. My left donut is missing, as is my right loved it, hated it, loved it, hated it scoot butt on the rug cat not kitten around</p>"
},
{
id: 2,
title: "Hipster Ipsum",
content:
"<p>Bushwick blue bottle scenester helvetica ugh, meh four loko. Put a bird on it lumbersexual franzen shabby chic, street art knausgaard trust fund shaman scenester live-edge mixtape taxidermy viral yuccie succulents. Keytar poke bicycle rights, crucifix street art neutra air plant PBR&B hoodie plaid venmo. Tilde swag art party fanny pack vinyl letterpress venmo jean shorts offal mumblecore. Vice blog gentrify mlkshk tattooed occupy snackwave, hoodie craft beer next level migas 8-bit chartreuse. Trust fund food truck drinking vinegar gochujang.</p>"
},
{
id: 3,
title: "Cupcake Ipsum",
content:
"<p>Icing dessert soufflé lollipop chocolate bar sweet tart cake chupa chups. Soufflé marzipan jelly beans croissant toffee marzipan cupcake icing fruitcake. Muffin cake pudding soufflé wafer jelly bear claw sesame snaps marshmallow. Marzipan soufflé croissant lemon drops gingerbread sugar plum lemon drops apple pie gummies. Sweet roll donut oat cake toffee cake. Liquorice candy macaroon toffee cookie marzipan.</p>"
}
],
selectedPost: null
};
},
template: `
<div class="posts-tab">
<ul class="posts-sidebar">
<li
v-for="post in posts"
v-bind:key="post.id"
v-bind:class="{ selected: post === selectedPost }"
v-on:click="selectedPost = post"
>
{{ post.title }}
</li>
</ul>
<div class="selected-post-container">
<div
v-if="selectedPost"
class="selected-post"
>
<h3>{{ selectedPost.title }}</h3>
<div v-html="selectedPost.content"></div>
</div>
<strong v-else>
Click on a blog title to the left to view it.
</strong>
</div>
</div>
`
});
Vue.component("tab-archive", {
template: "<div>Archive component</div>"
});
new Vue({
el: "#dynamic-component-demo",
data: {
currentTab: "Posts",
tabs: ["Posts", "Archive"]
},
computed: {
currentTabComponent: function() {
return "tab-" + this.currentTab.toLowerCase();
}
}
});
</script>
</body>
</html>
2、包含include和排除exclude属性
<KeepAlive>
默认会缓存内部的所有组件实例,但我们可以通过 include
和 exclude
来定制该行为。
include
和 exclude
属性允许组件有条件的选择性地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
include
- 只有名称匹配的组件会被缓存。exclude
- 任何名称匹配的组件都不会被缓存。
<!-- 逗号分隔字符串 -->
<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
选项,如果 name
选项不可用,则匹配它的局部注册名称 (父组件 components
选项的键值)。匿名组件不能被匹配。
以上代码中a和b均为两个组件的组件名。
3、最大缓存实例数
我们可以通过传入 max
prop 来限制可被缓存的最大组件实例数。<KeepAlive>
的行为在指定了 max
后类似一个 LRU 缓存:如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。
<KeepAlive :max="10">
<component :is="activeComponent" />
</KeepAlive>
4、缓存实例的生命周期
当一个组件实例从 DOM 上移除但因为被 <KeepAlive>
缓存而仍作为组件树的一部分时,它将变为不活跃状态而不是被卸载。
当一个组件实例作为缓存树的一部分插入到 DOM 中时,它将重新被激活。
一个持续存在的组件可以通过 activated() 和 deactivated() 注册相应的两个状态的生命周期钩子:
<script setup>
import { onActivated, onDeactivated } from 'vue'
onActivated(() => {
// 调用时机为首次挂载
// 以及每次从缓存中被重新插入时
})
onDeactivated(() => {
// 在从 DOM 上移除、进入缓存
// 以及组件卸载时调用
})
</script>
请注意:
-
onActivated
在组件挂载时也会调用,并且onDeactivated
在组件卸载时也会调用。 -
这两个钩子不仅适用于
<KeepAlive>
缓存的根组件,也适用于缓存树中的后代组件。