Vue.js: 错误处理与调试

最后更新:2026-08-26

错误处理是任何生产级应用的必备能力——应用崩了能快速定位、优雅降级、通知用户。Vue 3 提供了多层次错误处理:errorHandler(全局)、onErrorCaptured(局部)、errorCaptured 钩子(组件级)。

调试和性能优化同样重要——Vue DevTools 是必备工具,能让你看清组件树、状态、事件、性能瓶颈。

1. 你将学到


2. 一个白屏崩溃"找不到原因"事件

(1) 痛点:1 个 API 报错,整个页面空白

Alice 的后台出了 1 个严重 Bug:

JS
// ProductList.vue
const products = ref([])
onMounted(async () => {
  const res = await fetch('/api/products')
  products.value = await res.json()  // ❌ 后端返回非 JSON → 报错
})

用户体验:

产品经理 Charlie:

"Alice,客户抱怨页面白屏。我们需要:1)不让整个页面崩溃,2)显示错误信息,3)上报到监控系统。"

(2) Vue 错误边界解法

VUE
<!-- 父组件:错误边界 -->
<template>
  <ErrorBoundary>
    <ProductList />
  </ErrorBoundary>
</template>

<!-- ErrorBoundary.vue -->
<script setup>
const { onErrorCaptured, ref } = Vue
const error = ref(null)

onErrorCaptured((err, instance, info) => {
  console.error('Caught:', err)
  // 1. 显示错误信息
  error.value = err.message
  // 2. 上报到 Sentry
  Sentry.captureException(err)
  // 3. 阻止向上传播
  return false
})

const retry = () => { error.value = null }
</script>

<template>
  <div v-if="error" class="error">
    <h3>⚠️ Something went wrong</h3>
    <p>{{ error }}</p>
    <button @click="retry">Retry</button>
  </div>
  <slot v-else />
</template>

用户体验:

(3) 收益

加上错误处理后:


3. 3 层错误处理

(1) 全局错误处理:app.config.errorHandler

JS
// main.js
const { createApp } = Vue
import App from './App.vue'

const app = createApp(App)

// ✅ 全局错误处理
app.config.errorHandler = (err, instance, info) => {
  console.error('Global error:', err)
  console.log('Component:', instance)
  console.log('Info:', info)  // 'render' / 'watch' / 'lifecycle hook'
  
  // 上报到 Sentry
  Sentry.captureException(err)
  
  // 用户通知
  showErrorNotification('Something went wrong')
}

(2) 组件级错误:onErrorCaptured

VUE
<!-- ErrorBoundary.vue -->
<script setup>
const { onErrorCaptured, ref } = Vue

const error = ref(null)

// ✅ 捕获子组件错误
onErrorCaptured((err, instance, info) => {
  console.error('Boundary caught:', err)
  error.value = {
    message: err.message,
    stack: err.stack,
    info
  }
  
  // 阻止向上传播
  return false
})

const reset = () => { error.value = null }
</script>

<template>
  <div v-if="error" class="error-boundary">
    <h3>⚠️ {{ error.message }}</h3>
    <details>
      <summary>Stack trace</summary>
      <pre>{{ error.stack }}</pre>
    </details>
    <button @click="reset">Retry</button>
  </div>
  <slot v-else />
</template>

(3) 错误层级对比

层级 API 捕获范围 适用
全局 app.config.errorHandler 所有未捕获错误 生产环境必须
组件 onErrorCaptured 子组件错误 局部错误边界
异步 try/catch / window.onunhandledrejection Promise 错误 手动处理

(4) 5 大错误来源

JS
// 1. 渲染错误(模板语法错)
app.config.errorHandler = (err, instance, info) => {
  if (info === 'render') console.error('Render error:', err)
}

// 2. 生命周期钩子错误
if (info === 'mounted') console.error('Mounted error:', err)

// 3. watch 回调错误
if (info === 'watcher callback') console.error('Watch error:', err)

// 4. 自定义指令错误
if (info === 'directive') console.error('Directive error:', err)

// 5. 事件处理错误
if (info === 'v-on handler') console.error('Event error:', err)

4. Vue DevTools 调试

(1) 4 大核心面板

面板 功能 用途
Components 组件树、状态、props、emits 看清组件结构、调试数据
Timeline 事件、生命周期、性能 追踪事件流、性能瓶颈
Pinia/Vuex Store 状态 调试全局状态
Routes 路由历史 调试路由跳转

(2) Components 面板使用

TEXT 📖 仅展示
1. 打开 DevTools(F12 / Cmd+Opt+I)
2. 切换到 Vue 标签
3. 点击组件树中的组件
4. 右侧显示:
   - State(响应式数据)
   - Props
   - Emits
   - Slots
   - Lifecycle

(3) 5 大 DevTools 技巧

JS
// 1. 实时修改 state(开发模式)
// DevTools 中直接编辑,看组件实时响应

// 2. 时间旅行(Pinia)
// 切换到 Pinia 面板 → Base → 可以回放每一步 state 变化

// 3. 性能标记
// import { markRaw } from 'vue'
// 大数据对象用 markRaw 标记,DevTools 不会深遍历

// 4. 组件 highlight
// DevTools → 右上角"眼睛"图标 → 鼠标悬停高亮组件

// 5. 路由跳转
// DevTools → Routing 标签 → 看每次跳转的 path + params

(4) 安装 Vue DevTools

BASH
# Chrome 扩展
# https://chromewebstore.google.com/detail/vuejs-devtools/odjccnclnlddjlajjphfdmhnlhaglgki

# Firefox 扩展
# https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/

# 或独立应用(推荐)
# https://devtools.vuejs.org/

5. 性能分析

(1) Vue 3 性能 API

JS
const { onMounted, onUnmounted } = Vue

onMounted(() => {
  performance.mark('app-start')
  
  // 你的代码
  loadData()
  
  performance.mark('app-end')
  performance.measure('app-load', 'app-start', 'app-end')
  
  const measure = performance.getEntriesByName('app-load')[0]
  console.log(`App loaded in ${measure.duration}ms`)
})

(2) 5 大性能优化技巧

JS
// 1. v-once:只渲染一次
<h1 v-once>{{ title }}</h1>

// 2. v-memo:缓存子树
<div v-memo="[item.id, item.updatedAt]">
  <!-- 只在 id 或 updatedAt 变化时重渲染 -->
</div>

// 3. shallowRef:大数据不深响应
const bigList = shallowRef([...10000 items])

// 4. markRaw:第三方库不响应
const map = markRaw(new Map())

// 5. 懒加载:路由 / 组件
const Heavy = defineAsyncComponent(() => import('./Heavy.vue'))

(3) 5 大性能指标

指标 目标 测量方法
FCP(首次内容渲染) < 1.8s Lighthouse
LCP(最大内容渲染) < 2.5s Lighthouse
TTI(可交互时间) < 3.8s Lighthouse
TBT(总阻塞时间) < 200ms Lighthouse
CLS(布局偏移) < 0.1 Lighthouse

6. Sentry 集成

(1) 安装

BASH
npm install @sentry/vue @sentry/tracing

(2) main.js 配置

JS
const { createApp } = Vue
import * as Sentry from '@sentry/vue'
import { Integrations } from '@sentry/tracing'
import App from './App.vue'

const app = createApp(App)

// 1. 初始化 Sentry(app 必须先创建)
Sentry.init({
  app,
  dsn: 'https://your-dsn@sentry.io/123',
  integrations: [
    new Integrations.BrowserTracing()
  ],
  tracesSampleRate: 1.0,
  // 生产环境降低采样
  // tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0
  
  // Vue 特定配置
  logErrors: true,
  release: '1.0.0',
  environment: process.env.NODE_ENV
})

// 2. 全局错误上报
app.config.errorHandler = (err, instance, info) => {
  Sentry.captureException(err, {
    extra: {
      component: instance?.$options.name,
      info
    }
  })
}

(3) Source Map 配置

JS
// vite.config.js
export default {
  build: {
    sourcemap: true  // 生产环境也生成 source map
  }
}

// Sentry 上传 source map
// @sentry/cli releases -o your-org -p your-project files upload-sourcemaps ./dist

(4) 5 大 Sentry 功能

功能 用途
错误监控 自动捕获所有错误,仪表盘查看
性能追踪 慢请求、Slow DB 查询定位
会话回放 用户操作录屏,看错误现场
发布健康 每次发版错误率对比
告警 Slack / Email 通知

7. 完整示例:5 大调试技巧

▶ 示例:3 层错误处理(CDN 可演示 ErrorBoundary)

HTML 📖 仅展示
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

<style>
.btn { padding: 6px 12px; margin: 4px; background: #42b883; color: white; border: none; border-radius: 4px; cursor: pointer; }
.error { padding: 1rem; background: #fee; border: 1px solid #fcc; color: #c00; border-radius: 4px; margin: 4px 0; }
.buggy { padding: 1rem; background: #f0f9ff; border-radius: 4px; }
</style>

<div id="app">
  <button class="btn" @click="triggerError = !triggerError">
    {{ triggerError ? '恢复' : '触发子组件错误' }}
  </button>

  <error-boundary>
    <p>ErrorBoundary 之外的组件 - 正常工作</p>
  </error-boundary>

  <error-boundary>
    <buggy-component v-if="triggerError"></buggy-component>
    <p v-else class="buggy">ErrorBoundary 内的子组件 - 正常</p>
  </error-boundary>
</div>

<script>
const { createApp, ref, onErrorCaptured } = Vue

// ✅ ErrorBoundary 组件
const ErrorBoundary = {
  setup(_, { slots }) {
    const error = ref(null)
    onErrorCaptured((err) => {
      error.value = err
      return false   // 阻止向上传播
    })

    function reset() { error.value = null }

    return { error, reset }
  },
  template: `
    <div>
      <div v-if="error" class="error">
        ⚠️ Error caught: {{ error.message }}
        <button @click="reset">重试</button>
      </div>
      <slot v-else></slot>
    </div>
  `
}

// 故意出错的子组件
const BuggyComponent = {
  setup() {
    // 模拟错误:访问 undefined.value
    const data = ref(null)
    return { data }
  },
  template: '<div>{{ data.value.foo }}(会报错)</div>'
}

const App = {
  components: { ErrorBoundary, BuggyComponent },
  setup() {
    const triggerError = ref(false)
    return { triggerError }
  }
}

createApp(App).mount('#app')
</script>
逻辑代码 56 行(超过 40 行限制,仅展示)

▶ 示例:Vue 3 全局错误处理(⚠️ 需 Vite 项目 main.js)

JS
// main.js
app.config.errorHandler = (err, instance, info) => {
  console.error('[Global]', err, info)
  // 上报到 Sentry / 自己的日志服务
  // Sentry.captureException(err)
}
▶ 试一试

▶ 示例:5 大错误来源(info 字段)

info 字段 含义 例子
'render' 渲染错误 模板引用未定义变量
'mounted' / 'updated' 生命周期错误 onMounted 中访问 DOM 失败
'watcher callback' watch 错误 watch 回调异常
'directive' 指令错误 自定义指令 mounted 异常
'v-on handler' 事件错误 @click 处理函数 throw

▶ 示例:5 大性能优化(速查)

JS
// 1. v-once(只渲染一次)
<h1 v-once>{{ title }}</h1>

// 2. v-memo(缓存)
<div v-memo="[item.id]">...</div>

// 3. shallowRef(浅响应)
const list = shallowRef([...])

// 4. markRaw(不响应)
const map = markRaw(new Map())

// 5. 异步组件(懒加载)
const Heavy = defineAsyncComponent(() => import('./Heavy.vue'))
▶ 试一试

▶ 示例:5 个常见错误速查

错误 现象 解决
白屏崩溃 1 个组件错全挂 用 ErrorBoundary 包裹
错误吞掉 子组件静默失败 onErrorCaptured 不要忘 return false
Source Map 缺失 生产错误无法定位 vite build sourcemap: true
性能差 列表 1000 项卡顿 v-memo + shallowRef
内存泄漏 组件销毁后定时器还在 onUnmounted 清理

▶ 示例:5 大调试场景

场景 工具
组件状态异常 Vue DevTools → State
事件不触发 Vue DevTools → Timeline
路由跳转错 DevTools → Routing
生产环境崩溃 Sentry 仪表盘
性能慢 Lighthouse + DevTools Performance

❓ 常见问题

Q errorHandler 能捕获异步错误吗?
A 不能。errorHandler 只捕获 Vue 内部的同步错误。异步错误(Promise / setTimeout)需要 try/catch 或 window.addEventListener('unhandledrejection')
Q onErrorCaptured 必须 return false 吗?
A 不是必须。return false 阻止错误向上传播。return true(或不 return)让错误继续向上传播到全局 errorHandler。
Q Vue DevTools 在生产环境能用吗?
A 能。生产构建会自动启用 DevTools(不影响性能)。但建议在生产环境用 Vue.config.devtools = false 关闭(避免暴露内部结构)。
Q Sentry 怎么收费?
A 免费版每月 5,000 events + 10,000 performance transactions。中型项目够用。超出后按量计费。
Q v-memo 和 v-for 怎么配合?
A <div v-for="item in items" :key="item.id" v-memo="[item.id, item.updatedAt]">,只有 id 或 updatedAt 变化时才重渲染这个 div。
Q 怎么调试 SSR 应用?
A VS Code 调试器 + Node.js inspect 模式。或 Sentry 捕获服务端错误。或在 Nuxt 3 中用 Nitro 调试工具。
Q onErrorCaptured 在 Vue 3 和 Vue 2 区别?
A Vue 2 是 errorCaptured 钩子,Vue 3 是 onErrorCaptured 组合式 API。Vue 3 还新增全局 app.config.errorHandler

📖 小节


📝 作业

  1. 基础题(难度⭐) 实现一个 ErrorBoundary 组件:

    • onErrorCaptured 捕获子组件错误
    • 显示友好的错误页面
    • 提供"重试"按钮
  2. 进阶题(难度⭐⭐) 实现完整的错误处理系统:

    • 全局 errorHandler 上报到控制台
    • 组件级 ErrorBoundary
    • 异步错误 try/catch
    • 5 种错误来源分类
  3. 挑战题(难度⭐⭐⭐) 实现完整的"生产级"调试 + 错误监控:

    1. ErrorBoundary 组件 + 3 个不同位置
    2. Sentry 集成(生产环境)
    3. Source Map 配置
    4. Vue DevTools 5 大调试技巧
    5. 5 大性能优化(v-memo / shallowRef / markRaw / 懒加载 / v-once)
    6. 5 大性能指标监控(Lighthouse 集成)
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏