🌀 今日秘技:Teleport 与 Suspense の时空魔法
1. Teleport 任意门
<template>
<!-- 🚪 将组件传送到 body 末尾 -->
<Teleport to="body">
<div class="modal">
<h2>重要通知!🎉</h2>
<button @click="close">关闭</button>
</div>
</Teleport>
<!-- 🪐 传送到自定义容器 -->
<Teleport :to="isMobile ? '#mobile-menu' : '#desktop-menu'">
<NavBar />
</Teleport>
</template>
<script setup>
// 动态控制传送位置
const isMobile = useMediaQuery('(max-width: 768px)')
</script>
<style scoped>
.modal {
position: fixed;
z-index: 999;
/* 样式不再受父组件影响! */
}
</style>
🔔 核心场景:
- 模态框/通知栏全局展示
- 跨布局层级组件渲染
- 响应式动态切换渲染位置
2. Suspense 悬念结界
<template>
<!-- 🛡️ 异步组件加载结界 -->
<Suspense>
<template #default>
<AsyncDashboard />
</template>
<template #fallback>
<div class="skeleton-loader">🌀 加载中...</div>
</template>
</Suspense>
<!-- 🔥 多异步依赖管理 -->
<Suspense :timeout="3000">
<template #default>
<ArticleContent :id="articleId" />
<CommentList :id="articleId" />
</template>
</Suspense>
</template>
<script setup>
// 异步组件定义
const AsyncDashboard = defineAsyncComponent(() =>
import('./Dashboard.vue').then(comp => {
// 模拟网络延迟
return new Promise(resolve =>
setTimeout(() => resolve(comp), 1500)
)
})
)
</script>
🔔 高阶技巧:
- 配合
defineAsyncComponent
实现代码分割 - 通过
timeout
属性设置加载超时 - 嵌套使用管理复杂异步依赖链
❄️ 冷知识:Suspense の心跳检测
// 监听异步状态变化
import { onServerPrefetch } from 'vue'
// 服务端数据预取
onServerPrefetch(async () => {
await fetchData()
})
// 客户端心跳检测
const { isPending } = useSuspense()
watch(isPending, (loading) => {
console.log(loading ? '🌀 数据加载中...' : '✨ 数据就绪!')
})
🌟 实验室时空装置
实现智能错误边界
<template>
<Suspense @resolve="logSuccess" @fallback="logLoading" @pending="logPending">
<ErrorBoundary>
<AsyncComponent />
</ErrorBoundary>
</Suspense>
</template>
<script setup>
const logSuccess = () => console.log('✅ 数据加载成功')
const logLoading = () => console.log('⏳ 进入加载状态')
const logPending = () => console.log('🔄 等待异步依赖')
// 错误边界组件
const ErrorBoundary = {
setup(_, { slots }) {
const error = ref(null)
const handleError = (err) => {
error.value = err
console.error('🔥 组件崩溃:', err)
}
return () => {
return error.value
? h('div', '😱 紧急修复界面')
: slots.default?.()
}
}
}
</script>
明日秘典:《VueUse 魔法道具库——30个提升效率の神器》 🧰
(留言告诉我你最想拥有的 Vue 超能力,本魔导师为你定制代码咒语!🔮)
🛎️ 本日避坑指南:
- Teleport 的 CSS 陷阱
/* ❌ 父组件的样式可能污染传送内容 */
.parent-class .modal {
/* 失效!因为 modal 已被传送到外层 */
}
/* ✅ 始终使用 scoped 样式或全局样式 */
.modal { /* 全局样式 */ }
:deep(.modal) { /* scoped 穿透 */ }
- Suspense 的 SSR 限制
// ❌ 服务端渲染时无法显示 fallback
// ✅ 需在服务端预先加载数据
export async function serverPrefetch() {
await store.dispatch('fetchData')
}
- 异步组件缓存策略
// 🚀 配置加载缓存
const AsyncComp = defineAsyncComponent({
loader: () => import('./HeavyComponent.vue'),
delay: 200, // 延迟显示 loading
timeout: 3000, // 超时时间
suspensible: false // 禁用 Suspense 控制
})
- 多层 Teleport 优先级
<!-- 后写的 Teleport 会覆盖先写的 -->
<Teleport to="#target">内容A</Teleport>
<Teleport to="#target">内容B</Teleport>
<!-- 最终显示内容B -->