teleport 须外层包裹 transition,v-if 置于 transition 内根元素上,动画样式需非 scoped 或 css modules,严格定义 fade-enter/from/leave/to 类并显式声明 transition。

Vue 的 Teleport 本身不处理动画,但它和 <transition></transition> 配合得非常自然——关键在于结构顺序、挂载时机和样式作用域的协同控制。只要位置对、触发准、样式稳,淡入淡出就能干净利落地生效。
结构必须是 Teleport 包 Transition,而不是反过来
常见错误是把 v-if 放在 Teleport 外层,或让 Transition 包着 Teleport。正确嵌套是:
-
<teleport to="body"></teleport>最外层,确保 DOM 移动到位 -
<transition name="fade"></transition>紧贴其内,包裹弹窗根容器 -
v-if必须写在Transition内部最外层元素上(如<div class="modal" v-if="visible">) <p>这样 Vue 才能在 DOM 真实挂载到 <code>body后,再触发进入/离开动画;否则动画可能在未挂载节点上执行,直接失效。淡入淡出样式要写在非 scoped 标签里
因为
Teleport把内容送到了body,脱离了当前组件的样式作用域。如果用<style scoped></style>,生成的属性选择器(如.modal[data-v-xxx])无法匹配到新位置的 DOM,动画类就不起作用。- 推荐写法:
<style></style>(不加scoped),配合语义化类名如.fade-enter-active - 或者使用 CSS Modules,显式导入类名并绑定到元素上
- 避免依赖父级继承的 opacity 或 transition,所有动画属性都显式声明
动画类名规则要严格对应
Vue 会自动注入四类 class,按生命周期插入/移除:
-
fade-enter-from:元素插入前的状态(如opacity: 0) -
fade-enter-active:整个进入过程的过渡属性(如transition: opacity 0.25s ease) -
fade-leave-from:离开开始时的状态(opacity: 1) -
fade-leave-to:离开结束时的目标状态(opacity: 0)
注意:
-active类必须包含transition声明,否则没有过渡效果;from和to类只负责起始/终点样式。额外细节让效果更可靠
真实项目中容易忽略但影响体验的点:
- 弹窗根元素需设
position: fixed+ 显式z-index,避免因父容器 transform 导致定位偏移 - 遮罩层(
.modal-overlay)建议用backdrop-filter: blur(4px)提升质感 - 关闭时若需点击遮罩关闭,确保遮罩层事件捕获正常(
@click.self可靠) - 多个弹窗叠加时,用全局 zIndex 计数器动态分配,防止淡出过程中被新弹窗盖住
- 推荐写法:











