Skip to content

错误边界

<NuxtErrorBoundary> 用于捕获子组件中的运行时错误,防止错误向上冒泡导致整个页面崩溃。它让页面可以"局部降级"——某个组件出错了,其他部分仍然正常工作。

为什么需要错误边界?

没有 NuxtErrorBoundary有 NuxtErrorBoundary
一个组件崩溃 → 整个页面白屏一个组件崩溃 → 显示 fallback,其他正常
用户必须刷新页面用户可以重试或继续使用
错误影响所有功能错误被隔离在局部

错误边界的核心思想

隔离错误——把错误限制在最小范围内,不影响页面的其他部分。

类比

飞机的隔舱设计——一个舱室失压不会影响整个飞机。NuxtErrorBoundary 就是组件的隔舱。

基本用法

vue
<template>
  <NuxtErrorBoundary>
    <!-- 可能出错的组件 -->
    <UnstableComponent />

    <!-- 错误时的 fallback -->
    <template #error="{ error, clearError }">
      <div class="error-fallback">
        <p>组件加载失败:{{ error?.message }}</p>
        <button @click="clearError">重试</button>
      </div>
    </template>
  </NuxtErrorBoundary>
</template>

NuxtErrorBoundary 的工作原理

  1. 正常情况:渲染子组件
  2. 子组件抛出运行时错误:捕获错误,渲染 #error 插槽
  3. 调用 clearError():重新渲染子组件(重试)

#error 插槽

#error 插槽提供两个参数:

参数类型说明
errorError | undefined捕获的错误对象
clearError() => void清除错误,重新渲染子组件

自定义 fallback 样式

vue
<template>
  <NuxtErrorBoundary>
    <ChartComponent :data="chartData" />

    <template #error="{ error, clearError }">
      <div class="chart-error">
        <div class="error-icon">📊</div>
        <p>图表加载失败</p>
        <p class="error-detail">{{ error?.message }}</p>
        <button @click="clearError" class="retry-btn">重新加载</button>
      </div>
    </template>
  </NuxtErrorBoundary>
</template>

事件处理

通过 @error 事件监听错误,用于上报到监控系统:

vue
<template>
  <NuxtErrorBoundary @error="onError">
    <MapComponent />
  </NuxtErrorBoundary>
</template>

<script setup>
function onError(error) {
  console.error('组件错误:', error)

  // 上报到 Sentry / 其他监控
  reportToSentry(error)
}
</script>

@error 事件的用途

  • 记录错误日志
  • 上报到错误监控(Sentry、Bugsnag 等)
  • 发送告警通知

@error#error 插槽的区别

  • @error:事件回调,用于处理错误(日志、上报)
  • #error 插槽:UI 模板,用于显示 fallback

完整示例——仪表盘页面

vue
<template>
  <div class="dashboard">
    <h1>仪表盘</h1>

    <!-- 统计卡片:独立错误边界(失败不影响其他部分) -->
    <NuxtErrorBoundary @error="handleStatsError">
      <StatsCards />
      <template #error>
        <div class="card-error">统计数据加载失败</div>
      </template>
    </NuxtErrorBoundary>

    <!-- 图表:独立错误边界 -->
    <NuxtErrorBoundary @error="handleChartError">
      <LazyChartComponent />
      <template #error="{ clearError }">
        <div class="chart-error">
          <p>图表加载失败</p>
          <button @click="clearError">重试</button>
        </div>
      </template>
    </NuxtErrorBoundary>

    <!-- 数据表格:独立错误边界 -->
    <NuxtErrorBoundary @error="handleTableError">
      <DataTable :data="tableData" />
      <template #error>
        <div class="table-error">数据表格加载失败</div>
      </template>
    </NuxtErrorBoundary>
  </div>
</template>

<script setup>
function handleStatsError(error) {
  console.error('Stats error:', error)
  reportToSentry(error)
}

function handleChartError(error) {
  console.error('Chart error:', error)
  reportToSentry(error)
}

function handleTableError(error) {
  console.error('Table error:', error)
  reportToSentry(error)
}
</script>

这个示例展示了错误边界的核心价值

  • 图表崩溃 → 统计卡片和表格仍然正常
  • 表格崩溃 → 图表和统计卡片仍然正常
  • 每个区域独立容错,互不影响

推荐模式

仪表盘、后台管理等包含多个独立模块的页面,每个模块都用 NuxtErrorBoundary 包裹。

NuxtErrorBoundary vs error.vue

特性NuxtErrorBoundaryerror.vue
作用范围子组件全局
错误类型运行时错误所有错误
显示方式局部 fallback全屏错误页面
恢复方式clearError()clearError({ redirect })
可定制性高(每个边界独立)低(统一页面)
对用户体验的影响小(局部降级)大(整个页面替换)
适用场景组件级容错全局兜底

两者配合使用

  • NuxtErrorBoundary:第一道防线,捕获组件级错误,局部降级
  • error.vue:最后防线,捕获所有未处理的错误,全屏展示

防御策略

  1. 优先用 try/catch 处理已知可能的错误(如 API 调用)
  2. NuxtErrorBoundary 包裹可能不稳定的组件
  3. error.vue 作为最后的兜底

使用场景

场景原因示例
第三方组件可能不稳定地图、图表、富文本编辑器
浏览器 API 依赖SSR 时可能报错windowdocumentcanvas
重交互组件复杂交互容易出错拖拽、画布、3D 渲染
模块化容错各区域独立仪表盘、后台管理
懒加载组件加载可能失败LazyXxx 组件

注意事项

  1. 只能捕获子组件错误:不能捕获自身或父组件的错误
  2. 异步错误不捕获setTimeoutPromise 中的错误不会触发(需用 try/catch
  3. Hydration 错误:部分 Hydration 不匹配错误可能不触发
  4. clearError() 会重新渲染组件:如果组件的 bug 没有修复,可能再次触发错误

知识脉络

text
错误页面 → 错误创建与抛出 → 错误清除 → 你在这里:错误边界

                                      ├─→ 相关:内置组件速查 → NuxtErrorBoundary

                                      └─→ 相关:插件与中间件(全局错误处理)

基于 Nuxt 4 官方文档整理编写