前端小食堂 | Day14 - Vue 3 の传送门与悬念

发布于:2025-03-15 ⋅ 阅读:(18) ⋅ 点赞:(0)

🌀 今日秘技: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 超能力,本魔导师为你定制代码咒语!🔮)


🛎️ 本日避坑指南

  1. Teleport 的 CSS 陷阱
/* ❌ 父组件的样式可能污染传送内容 */  
.parent-class .modal {  
  /* 失效!因为 modal 已被传送到外层 */  
}  

/* ✅ 始终使用 scoped 样式或全局样式 */  
.modal { /* 全局样式 */ }  
:deep(.modal) { /* scoped 穿透 */ }  
  1. Suspense 的 SSR 限制
// ❌ 服务端渲染时无法显示 fallback  
// ✅ 需在服务端预先加载数据  
export async function serverPrefetch() {  
  await store.dispatch('fetchData')  
}  
  1. 异步组件缓存策略
// 🚀 配置加载缓存  
const AsyncComp = defineAsyncComponent({  
  loader: () => import('./HeavyComponent.vue'),  
  delay: 200, // 延迟显示 loading  
  timeout: 3000, // 超时时间  
  suspensible: false // 禁用 Suspense 控制  
})  
  1. 多层 Teleport 优先级
<!-- 后写的 Teleport 会覆盖先写的 -->  
<Teleport to="#target">内容A</Teleport>  
<Teleport to="#target">内容B</Teleport>  
<!-- 最终显示内容B -->  

网站公告

今日签到

点亮在社区的每一天
去签到