Vue3 的 KeepAlive 和 Teleport 内置组件
Vue3 提供了一些可以直接使用的内置组件,包括 Transition、TransitionGroup、KeepAlive、Teleport、Suspense。之前写了 Transition 和 TransitionGroup ,这里继续来写 KeepAlive 和 Teleport。
KeepAlive
在使用 component
元素配合 is
切换组件时,组件是会被销毁的,组件销毁时也会同时销毁相关的数据。KeepAlive 的作用就是在多个组件切换时缓存组件实例。
组件使用
下面使用 component
切换组件:
<template>
<div>
<button @click="tagName = 'tagPage1'">显示标签页1</button>
<button @click="tagName = 'tagPage2'">显示标签页2</button>
<component :is="tags[tagName]"></component>
</div>
</template>
<script setup>
import { ref } from "vue";
import tagPage1 from './components/tagPage1.vue';
import tagPage2 from './components/tagPage2.vue';
const tags = {tagPage1, tagPage2};
const tagName = ref('tagPage1');
</script>
上面的组件中引入了 tagPage1
和 tagPage2
组件,使用按钮可以在两个组件之间切换,效果如下:
tagPage1
和 tagPage2
是差不多的,两个组件中都有一个 count
变量用来保存数字,点击按钮数字就会 ++。我在切换组件后,之前组件的数据就会被销毁,count
的数字也会变为 0。
下面使用 KeepAlive 来缓存上面的 tagPage1
和 tagPage2
组件:
<KeepAlive>
<component :is="tags[tagName]"></component>
</KeepAlive>
我在两个组件之间切换时,组件的数据也不会丢失。
设置包含和排除组件
通过 include
和 exclude
属性可以设置包含和排除组件,include
是要包含的组件,exclude
是要排除的组件。
<!--include 可以传入组件对象名称,名称之间用逗号分隔-->
<KeepAlive include="tagPage1,tagPage3">
<component :is="tags[tagName]"></component>
</KeepAlive>
<!--也可以通过正则表达式传入名称-->
<KeepAlive :include="/tagPage1|tagPage3/">
<component :is="tags[tagName]"></component>
</KeepAlive>
<!--也可以通过数组传入名称-->
<KeepAlive :include="['tagPage1','tagPage3']">
<component :is="tags[tagName]"></component>
</KeepAlive>
exclude
排除的写法和 include
是一样的。
设置最大缓存数
通过 max
可以设置最大缓存实例数:
<KeepAlive :max="3">
<component :is="tags[tagName]"></component>
</KeepAlive>
如果缓存的组件超出了限制,访问次数少的组件就会被销毁。
缓存生命周期钩子
被 KeepAlive 缓存的组件,切换时只会移除页面上的 DOM 元素,移除元素后组件会变为 不活跃状态
,切换回来又会变为 活跃状态
。
KeepAlive 提供了两个钩子,在切换活跃状态时,可以通过钩子触发函数。
下面给 KeepAlive
内的组件添加钩子函数:
import { onActivated, onDeactivated } from "vue";
onActivated(() => {
alert('组件被切换为不活跃状态');
});
onDeactivated(() => {
alert('组件被切换为活跃状态');
});
组件第一次挂载时也会触发 onActivated
。
Teleport
Teleport 可以把一个组件的模板内容移动到组件 DOM 之外的区域。比如你在 App
组件引入了 B 组件,B 组件里又引入了 C 组件,你可以使用 Teleport 内置组件把 C 组件里的 template 模板内容直接移动到 body
下。
Teleport 主要的使用场景就是一些需要全屏显示的模态框或大图展示之类的,使用 Teleport
把组件模板移动到外层或 body
下,可以避免父组件或父元素的 CSS 样式影响到模态框的样式。
组件使用
下面是一个 App
组件,组件里包含多个 div
,我会在最深层的 div
中插入一个 imgModal
组件:
<template>
<div id="post-page">
<div class="content">
<imgModal />
</div>
</div>
</template>
<script setup>
import imgModal from './components/img-modal.vue';
</script>
下面是 imgModal
组件:
<template>
<div id="img-box">
<img src="https://www.misterma.com/img-admin/uploads/16867997522291.png" alt="大图">
</div>
</template>
在浏览器的开发者工具中可以看到 id
为 img-box
的元素是在 .content
里的:
下面给 id
为 img-box
的元素外添加 Teleport
组件,把 id
为 img-box
的元素直接移动到 body
下:
<template>
<Teleport to="body">
<div id="img-box">
<img src="https://www.misterma.com/img-admin/uploads/16867997522291.png" alt="大图">
</div>
</Teleport>
</template>
打开开发者工具看一下:
Teleport
的 to
可以是一个 CSS 选择器字符串,也可以是一个 DOM 对象,上面的 to="body"
就是把 Teleport
内的元素直接移动到 body
下。
Teleport 只会改变 DOM 的结构,不会改变组件间的逻辑关系,A 组件下的 B 组件使用 Teleport 把模板移动到 body 下,B 组件也还是 A 组件的子组件。Props、provide 和 inject 还是按照正常的组件关系使用。
禁用 Teleport
在有的情况下可能需要根据用户的设备或设置动态的启用或禁用 Teleport,Teleport
有一个 :disabled
属性,通过 :disabled
可以禁用 Teleport :
<Teleport to="body" :disabled="true"></Teleport>
多个 Teleport 移动到同一个元素下
多个 Teleport 也可以移动到同一个目标元素下:
<Teleport to="body">
<p>Mr. Ma's Blo www.misterma.com</p>
</Teleport>
<Teleport to="body">
<p>Github https://github.com/changbin1997</p>
</Teleport>
移动后的顺序还是和 Teleport 的顺序一样的:
<p>Mr. Ma's Blo www.misterma.com</p>
<p>Github https://github.com/changbin1997</p>
版权声明:本文为原创文章,版权归 Mr. Ma's Blog 所有,转载请联系博主获得授权。
本文地址:https://www.misterma.com/archives/927/
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。