前端面经-VUE3篇(五)--内置组件
一、Transition
<Transition>
是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:
- 由
v-if
所触发的切换 - 由
v-show
所触发的切换 - 由特殊元素
<component>
切换的动态组件 - 改变特殊的
key
属性
1、 基本用法
基本用法<template><button @click="show = !show">切换</button><Transition><p v-if="show">Hello World</p></Transition>
</template><script setup>
import { ref } from 'vue'
const show = ref(true)
</script>
v-if
控制显示隐藏,<Transition>
负责监听这个变化,并在“进入”和“离开”时应用 CSS 动画。
2、Vue 自动添加的 CSS 类名
当 <Transition>
触发时,它自动添加并移除以下 CSS 类名,你只需要写对应样式即可:
阶段 | 类名 | 用途说明 |
---|---|---|
进入开始 | .v-enter-from | 初始状态(如透明、缩小) |
进入中 | .v-enter-active | 过渡时持续作用的样式 |
进入结束 | .v-enter-to | 最终状态(如显示、放大) |
离开开始 | .v-leave-from | 开始隐藏前的状态 |
离开中 | .v-leave-active | 离开过程中应用的过渡 |
离开结束 | .v-leave-to | 完全隐藏后的样式 |
-
v-enter-from
:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。 -
v-enter-active
:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。 -
v-enter-to
:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是v-enter-from
被移除的同时),在过渡或动画完成之后移除。 -
v-leave-from
:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。 -
v-leave-active
:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。 -
v-leave-to
:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是v-leave-from
被移除的同时),在过渡或动画完成之后移除。
示例样式(淡入淡出)
.v-enter-from, .v-leave-to {opacity: 0;
}
.v-enter-to, .v-leave-from {opacity: 1;
}
.v-enter-active, .v-leave-active {transition: opacity 0.5s ease;
}
3、 设置名称(多种动画效果时)
你可以通过 name 属性设置前缀,代替 .v-xxx:
<Transition name="fade"><p v-if="show">Hello</p>
</Transition>
对应的类名变为:
.fade-enter-from
.fade-leave-active 等
4、自定义过渡 class
你也可以向 <Transition>
传递以下的 props 来指定自定义的过渡 class:
enter-from-class
enter-active-class
enter-to-class
leave-from-class
leave-active-class
leave-to-class
让你自己控制 <Transition>
使用的 CSS 类名,而不是默认的 .v-enter-from
、.v-leave-active
等。
✅ 用法示例:
结合 Animate.css 第三方库:
<Transitionenter-active-class="animate__animated animate__tada"leave-active-class="animate__animated animate__bounceOutRight"
><p v-if="show">hello</p>
</Transition>
👉 Vue 不会再用默认的 .v-xxx 类,而会用你传的 class。
5、同时使用 transition
和 animation
时声明 type
🌟作用:
明确告诉 Vue 应该监听 transitionend
还是 animationend
,避免冲突或提前结束。
<Transition type="animation"><div v-if="show">Hello</div>
</Transition>使用 CSS 动画(如 @keyframes)时
动画和过渡混用时,手动指定触发点
6、深层级过渡(嵌套元素动画)
🌟作用:
即使 <Transition>
只能包裹一个元素,但你可以通过选择器控制内部嵌套元素的动画。
<Transition name="nested"><div v-if="show" class="outer"><div class="inner">Hello</div></div>
</Transition>
.nested-enter-active .inner {transition: all 0.3s;
}
.nested-enter-from .inner {opacity: 0;transform: translateX(30px);
}
你还可以使用 transition-delay 实现渐进动画(staggered animation)。
7、JavaScript 钩子函数(@enter, @leave 等)
🌟作用:
用 JS 控制动画流程,比如使用动画库、动态设置样式、动画完成后执行逻辑。
<Transition@before-enter="onBeforeEnter"@enter="onEnter"@after-enter="onAfterEnter"@enter-cancelled="onEnterCancelled"@before-leave="onBeforeLeave"@leave="onLeave"@after-leave="onAfterLeave"@leave-cancelled="onLeaveCancelled"
><!-- ... -->
</Transition>
js
// 在元素被插入到 DOM 之前被调用
// 用这个来设置元素的 "enter-from" 状态
function onBeforeEnter(el) {}// 在元素被插入到 DOM 之后的下一帧被调用
// 用这个来开始进入动画
function onEnter(el, done) {// 调用回调函数 done 表示过渡结束// 如果与 CSS 结合使用,则这个回调是可选参数done()
}// 当进入过渡完成时调用。
function onAfterEnter(el) {}// 当进入过渡在完成之前被取消时调用
function onEnterCancelled(el) {}// 在 leave 钩子之前调用
// 大多数时候,你应该只会用到 leave 钩子
function onBeforeLeave(el) {}// 在离开过渡开始时调用
// 用这个来开始离开动画
function onLeave(el, done) {// 调用回调函数 done 表示过渡结束// 如果与 CSS 结合使用,则这个回调是可选参数done()
}// 在离开过渡完成、
// 且元素已从 DOM 中移除时调用
function onAfterLeave(el) {}// 仅在 v-show 过渡中可用
function onLeaveCancelled(el) {}
如果你使用 JS 钩子,并且不希望使用 CSS,记得加 :css="false"
。
8、可复用的过渡组件
🌟作用:
封装好 transition + CSS + JS,像普通组件一样使用。
优势:复用、维护方便、项目规范统一
<!-- MyTransition.vue -->
<Transition name="fade" @enter="onEnter"><slot></slot>
</Transition><!-- 使用 -->
<MyTransition><div v-if="show">内容</div>
</MyTransition>
二、TransitionGroup
1、什么是 <TransitionGroup>
<TransitionGroup>
是 Vue 提供的内置组件,用于在列表中的元素添加“进入/离开/移动”的动画效果。
2、和 <Transition>
的区别
特性 | <Transition> | <TransitionGroup> |
---|---|---|
用于单个元素或组件 | ✅ 是 | ❌ 否 |
用于多个列表项 | ❌ 否 | ✅ 是 |
支持元素位置移动动画 | ❌ 否 | ✅ 是 |
包裹内容限制 | 只能一个子元素 | 多个元素 |
3、什么时候用 <TransitionGroup>
?
使用场景:
-
渲染列表(如
v-for
)并需要进入/移除/移动动画 -
拖拽排序动画
-
列表项动态添加/删除时过渡
4、 基本用法
<template><button @click="add">添加</button><TransitionGroup name="fade" tag="ul"><li v-for="item in items" :key="item.id">{{ item.text }}</li></TransitionGroup>
</template><script setup>
import { ref } from 'vue'let id = 0
const items = ref([])function add() {items.value.push({ id: id++, text: `Item ${id}` })
}
</script><style>
.fade-enter-from, .fade-leave-to {opacity: 0;transform: translateY(20px);
}
.fade-enter-active, .fade-leave-active {transition: all 0.5s;
}
</style>
必须设置 :key
每个 v-for
渲染的元素都必须有唯一的 :key
,否则 Vue 无法正确跟踪哪个元素正在进入或离开。
tag 属性
默认 <TransitionGroup>
渲染成 <span>
标签,可以用 tag
指定你想要的元素:
<TransitionGroup tag="ul"> ... </TransitionGroup>
5、元素移动动画(独有特性)
如果你重新排序了列表,<TransitionGroup>
会为列表项添加一个 move
类名,用于实现移动动画:
.fade-move {transition: transform 0.5s;
}
Vue 会检测元素位置的变动,并用 transform 来产生平滑的“移动”动画。
6、删除动画的额外说明
元素删除时不是立即移除,而是:
-
添加
.fade-leave-from
→.fade-leave-to
-
执行动画
-
动画结束后移除 DOM
<TransitionGroup>
是 Vue 中专为多个元素的进出与移动动画设计的组件。它结合 v-for
与 key
,实现列表的“增删改查 + 动画”效果,是做炫酷 UI 动画不可或缺的利器。
三、keepAlive
1、什么是 <KeepAlive>
?
<KeepAlive>
是 Vue 提供的一个内置组件,用于缓存动态组件的状态,避免它们被频繁销毁和重新创建。
通俗讲就是:“不让组件每次显示/隐藏都重新加载,而是记住它上一次的状态”。
2、为什么要用 <KeepAlive>
?
✅ 不使用时:
每次切换组件,Vue 都会卸载旧的组件、重新创建新的组件,导致:
-
组件状态丢失
-
需要重新发送请求、重新初始化
✅ 使用 <KeepAlive>
:
-
Vue 会将被缓存的组件“保留在内存中”
-
切换回来时,组件保持原状态(不会重新 mounted)
3、基本用法
<template><KeepAlive><component :is="currentView" /></KeepAlive>
</template><script setup>
import A from './A.vue'
import B from './B.vue'
import { ref } from 'vue'const currentView = ref('A')// 可在按钮中切换组件
// currentView.value = 'B'
</script>
4、使用场景
场景 | 示例 |
---|---|
页面切换 | tab 页、路由视图 |
表单页面 | 不希望切换时清空输入内容 |
编辑器或富交互组件 | 保留光标位置、历史操作等状态 |
5、注意事项
-
<KeepAlive>
只能包裹一个组件(或<component :is="">
动态组件) -
不支持普通 HTML 元素或多个组件
-
它会缓存组件的实例、状态、生命周期,不是 DOM 节点
6、属性说明
1. include
:只缓存指定组件
<KeepAlive include="A,B"> <component :is="currentView" /> </KeepAlive>
2. exclude
:排除不缓存的组件
<KeepAlive exclude="C"> <component :is="currentView" /> </KeepAlive>
支持:
-
字符串(组件名)
-
正则表达式
-
数组
⚠️ 组件必须有 name(选项式 API 的
name
字段)才能识别!
3. max
:最多缓存多少个组件
<KeepAlive :max="2">...</KeepAlive>
超出 max
数量的组件会被缓存淘汰(LRU 机制)。
4、生命周期配合
使用 <KeepAlive>
后,组件有两个新的生命周期钩子:
生命周期 | 说明 |
---|---|
onActivated() | 被 <KeepAlive> 缓存后重新激活时调用 |
omDeactivated() | 被 <KeepAlive> 隐藏或切换时调用 |
export default {name: 'MyComponent',activated() {console.log('组件被激活')},deactivated() {console.log('组件被缓存/隐藏')}
}
适合用来:
-
重新拉取数据(如果需要)
-
清除定时器 / 暂停动画
<KeepAlive>
是用于缓存 Vue 组件实例的组件,可以避免状态丢失,提高性能,适用于路由视图、表单页、tab 页等多组件切换场景。
四、 Teleport
1、什么是 <Teleport>
?
<Teleport>
是 Vue 3 中的一个内置组件,用于将某部分组件的内容“传送”到 DOM 的其他位置进行渲染。
通俗理解:你写在 A 的组件内部的 HTML,最后却被“传送”到了页面上的 B 区域。
2、为什么需要 <Teleport>
?
在以下情况中你可能不希望某个元素被限制在组件的 DOM 结构里:
场景 | 问题 | 解决 |
---|---|---|
模态框、弹窗 | 被父组件限制 overflow: hidden | Teleport 到 <body> |
Toast 提示 | 渲染在按钮下方不合适 | Teleport 到固定区域 |
侧边栏、浮层 | 跟随滚动受限 | Teleport 到页面根部 |
3、基本语法
<Teleport to="body"><div class="modal">这是一个弹窗</div>
</Teleport>
📌 上面这段代码会把 div.modal 渲染到 <body> 中,而不是它在组件中的位置。
Teleport 的核心属性:to
<Teleport to="body">...</Teleport>
<Teleport to="#portal">...</Teleport>
-
to
接收一个CSS 选择器或 DOM 元素 -
必须指向一个已经存在的 DOM 节点
使用示例:模态框弹窗
<template><button @click="show = true">打开弹窗</button><Teleport to="body"><div v-if="show" class="modal"><p>这是一个全局弹窗</p><button @click="show = false">关闭</button></div></Teleport>
</template><script setup>
import { ref } from 'vue'
const show = ref(false)
</script><style>
.modal {position: fixed;top: 30%;left: 50%;transform: translateX(-50%);background: white;border: 1px solid #ccc;padding: 1rem;
}
</style>
虽然写在组件内部,但它最终出现在 <body>
中,避免了 CSS 限制。
4、Teleport 的适用场景总结
场景 | 描述 |
---|---|
弹窗 / 模态框 | 避免被父组件的样式影响,如 overflow: hidden |
Toast / 消息提示 | 放在固定区域(如右上角)不受限制 |
下拉菜单 / 选择器 | 保证在最上层显示、避免被遮挡 |
多层嵌套时需要脱离结构限制 | 比如点击卡片出现独立对话框 |
五、Suspense
1、什么是 <Suspense>
?
<Suspense>
是 Vue 3 引入的内置组件,用于在异步组件或 setup 函数中加载异步数据时显示“等待内容”,并在加载完成后自动切换显示内容。
通俗理解:在组件加载/准备数据的时候,先显示一个“加载中”占位,等准备好了再显示真正内容。
2、核心作用
功能 | 说明 |
---|---|
异步加载组件时显示备用内容 | 显示加载提示、骨架屏等 |
搭配 <script setup> 的 await 使用 | 用于 async setup 函数 |
管理多个子组件的加载流程 | 父组件等所有子组件加载完后再展示 |
3、基本用法
<template><Suspense><template #default><AsyncContent /></template><template #fallback><div>加载中...</div></template></Suspense>
</template><script setup>
import { defineAsyncComponent } from 'vue'const AsyncContent = defineAsyncComponent(() =>import('./AsyncContent.vue')
)
</script>
效果
-
AsyncContent
还没加载好 → 显示 fallback -
AsyncContent
加载完成 → 显示 default 插槽内容
4、何时会触发 Suspense?
-
异步组件(通过
defineAsyncComponent
或async setup()
) -
异步逻辑在
<script setup>
中使用await
-
组件内部
setup()
返回一个Promise
(比如从服务器加载数据)
5、Suspense 的典型场景
场景 | 描述 |
---|---|
异步组件加载 | 比如从远程 import 组件 |
异步初始化数据 | async setup() 中加载用户信息、配置等 |
页面首次加载骨架屏 | 显示 placeholder UI |
SSR 中流式渲染 | 提前展示部分可用内容 |