Vue3 中的 Teleport 和 KeepAlive:这两个内置组件到底怎么用

更新日期: 2026-04-28 阅读: 20 标签: 组件

做后台管理系统的同学一定遇到过这个问题:写了一个弹窗,结果被父级容器的 overflow: hidden 或者 transform: scale() 给整变形了。还有做多步骤表单的时候,用户填到第三步,一不小心点走了标签页,回来发现填的东西全没了。这两个坑,Vue3 的 Teleport 和 KeepAlive 就是来填的。


Teleport:让组件“穿墙”出去

Teleport 这个词就是“瞬间移动”的意思。Vue3 用它解决一个很实际的问题:让组件的 DOM 节点可以渲染到任意位置,但组件的逻辑关系保持不变。

举个例子。你的业务组件 A 嵌套在一个三层深的容器里,这个容器带了 overflow: hidden。你想让 A 里面的弹窗直接挂在 body 下面。以前你得用一些复杂手段,或者把弹窗的状态提到最顶层。现在用 Teleport,一行代码就搞定。

基本写法

<!-- 传送到 body -->
<Teleport to="body">
  <Modal :visible="showModal" />
</Teleport>

<!-- 传送到指定容器,disabled 可以动态开关 -->
<Teleport to="#overlay-container" :disabled="!isMobile">
  <Tooltip />
</Teleport>

Teleport 接受两个参数:to 指定要去哪里(填 CSS 选择器或者 body 关键字),disabled 控制要不要传送。

底层原理

Vue3 的组件实例和 DOM 节点是分开的。Teleport 做的事很简单:在渲染的时候,把子节点的 DOM 操作改到目标容器上。Vue 的响应式系统完全不受影响。你可以在 Teleport 里面正常用 provide/inject,父组件也能通过 ref 拿到子组件实例。

需要注意的地方

Teleport 的目标元素必须在它渲染之前就已经存在。如果目标是动态创建的,要用 nextTick 等它创建好了再渲染。


KeepAlive:让组件“活”下来

如果说 Teleport 是空间上的传送,那 KeepAlive 就是时间上的保存。它让组件在切换后不被销毁,而是缓存起来,下次切回来直接唤醒。

这个在 Tab 切换、路由缓存、多步骤表单里特别好用。用户填了五分钟的表单,因为手滑切到别的页面就全丢了,这种事太让人崩溃了。

生命周期变化

普通组件切换时,会走 unmounted 然后 mounted,状态全丢。被 KeepAlive 包住后,切换时走的是 deactivated 和 activated,组件实例和 DOM 都被缓存,状态还在。

import { onActivated, onDeactivated, ref } from 'vue'

const formData = ref({
  username: '',
  step: 1
});

onActivated(() => {
  console.log('组件复活了,状态还在:', formData.value);
});

onDeactivated(() => {
  console.log('组件被缓存了');
});

控制缓存:include、exclude、max

KeepAlive 给了三个参数来控制缓存:

<KeepAlive
  :include="['UserForm', 'UserProfile']"
  :exclude="['Detail']"
  :max="10"
>
  <component :is="currentComponent" />
</KeepAlive>

include 是只缓存谁,exclude 是不缓存谁,max 是最多缓存多少个。max 这个参数很实用,可以防止缓存太多导致内存占用过高。

注意命名

用 include 和 exclude 的时候,组件必须有 name。在 Vue3.3+ 里用 defineOptions 来声明:

defineOptions({ name: 'UserForm' });


两个一起用:全局弹窗系统

单独用其中一个已经很好了,两个组合起来才是真的大招。常见场景是全局弹窗系统:

  • 弹窗内容需要 Teleport 到 body,不被父级样式影响

  • 弹窗的状态需要 KeepAlive 缓存,切换路由不丢失

  • 用户填了一半的表单,关掉再打开,数据还在

<Teleport to="body">
  <KeepAlive>
    <template v-for="modal in modals" :key="modal.id">
      <component
        :is="modal.component"
        v-if="modal.visible"
        :visible="modal.visible"
      />
    </template>
  </KeepAlive>
</Teleport>


实际用法:多步骤表单加全局确认框

路由级缓存

<!-- App.vue -->
<KeepAlive :include="['OrderConfirm', 'AddressEdit', 'PaymentSelect']">
  <RouterView />
</KeepAlive>

几个建议

  • 不是所有页面都要缓存。列表页、详情页一般不需要,按需来就行

  • 在 onDeactivated 里清理定时器和事件监听,避免内存泄漏

  • Teleport 的目标尽量用一个固定的容器,不要动态创建


常见问题

Teleport 里的组件还能用父组件的 provide 吗?

能。Teleport 只改 DOM 位置,不改组件逻辑树。依赖注入、事件传递、ref 获取都不受影响。

KeepAlive 缓存的组件会释放内存吗?

不主动释放。但设了 max 之后,最久没用过的实例会被销毁,释放内存。

include 和 exclude 支持动态更新吗?

支持。它们是响应式的,可以根据用户操作动态调整。


总结

Teleport 打破 DOM 层级限制,让组件渲染到任意位置,逻辑关系不变。KeepAlive 让组件切换时不销毁,状态保留。两个一起用,全局弹窗、表单缓存、多 Tab 应用都能处理得很干净。

本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/13723

相关推荐

vue重新渲染组件(重置或者更新)

当数据通过异步操作后,对之前加载的数据进行变更后,发现数据不生效。A组件或者B组件触发数据更新,C组件数据更新了,但是C组件仍显示上一次数据。

Vuetify基于vue2.0,为移动而生的组件框架

Vuetify 支持SSR(服务端渲染),SPA(单页应用程序),PWA(渐进式Web应用程序)和标准HTML页面。 Vuetify是一个渐进式的框架,试图推动前端开发发展到一个新的水平。

React高阶组件中使用React.forwardRef的技巧

之前使用React.forwardRef始终无法应用于React高阶组件中,关键点就是React.forwardRef的API中ref必须指向dom元素而不是React组件。codepen实例请划到底部。

Vue使用Props绑定Object并且传参

通过Props 给子组件传变量,变量是对象时,子组件无法在首次打开时获取到传入对象数据,并且在父组件中改变对象的属性,子组件也是无法监听

Vue中插槽的作用_Vue组件插槽的使用以及调用组件内的方法

通过给组件传递参数, 可以让组件变得更加可扩展, 组件内使用props接收参数,slot的使用就像它的名字一样, 在组件内定义一块空间。在组件外, 我们可以往插槽里填入任何元素。slot-scope的作用就是把组件内的数据带出来

React Hook父组件获取子组件的数据/函数

我们知道在react中,常用props实现子组件数据到父组件的传递,但是父组件调用子组件的功能却不常用。文档上说ref其实不是最佳的选择,但是想着偷懒不学redux,在网上找了很多教程,要不就是hook的讲的太少

使用Vue 自定义文件选择器组件

文件选择元素是web上最难看的 input 类型之一。它们在每个浏览器中实现的方式不同,而且通常非常难看。这里有一个解决办法,就是把它封装成一个组件。

element-ui 的隐藏滚动组件el-scrollbar

为什么要用el-scrollbar,大家都知道,模拟一个滚动不难,而且市面上有很多这样的库。我考虑的,首先项目用的框架是Vue,然后用的组件库是Element,Element官网也有很多滚动

vue中prop属性传值解析

prop的定义:在没有状态管理机制的时候,prop属性是组件之间主要的通信方式,prop属性其实是一个对象,在这个对象里可以定义一些数据,而这些数据可以通过父组件传递给子组件。 prop属性中可以定义属性的类型,也可以定义属性的初始值。

写一个vue组件库_跟着element学习写组件

组件以插件的形式引入使用,当然,也可以直接在页面引入组件文件,两者按需使用。通过源码可知,vue不会重复安装同一个插件。以第一次安装为准,现在,可以在代码中使用组件啦~

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!