onErrorCaptured 是 Vue 3 中用于捕获未处理的子孙组件运行时错误的钩子,需满足错误发生在子孙组件、未被其自身捕获、当前组件定义了该钩子且为 JS 运行时异常等条件才触发。

onErrorCaptured 是 Vue 3 中用于在组件树中捕获子孙组件抛出的运行时错误的生命周期钩子,它不是在当前组件自身出错时触发,而是当其**任意后代组件(包括动态组件、插槽内容、递归子组件等)发生未被内部处理的 JavaScript 错误时**,由父级(或祖先)组件通过该钩子“拦截”并响应。
什么时候会触发 onErrorCaptured?
满足以下全部条件才会触发:
- 错误发生在当前组件的模板渲染、生命周期钩子、setup() 中的响应式副作用(如 watch)、事件处理函数等——但必须是该组件的子孙组件范围内;
- 该错误未被子孙组件自身的 try/catch 或 onErrorCaptured 捕获(即向上传播);
- 当前组件(或其某个祖先)定义了 onErrorCaptured 钩子;
- 错误类型为 JavaScript 运行时异常(如
throw new Error()、引用 undefined 属性、Promise rejection 未处理等),不包括编译错误或语法错误。
如何正确使用 onErrorCaptured?
在 setup() 中调用:
import { onErrorCaptured } from 'vue'
<p>export default {
setup() {
onErrorCaptured((error, instance, info) => {
console.error('捕获到子孙组件错误:', error)
console.log('出错组件实例:', instance)
console.log('错误类型信息:', info) // 如 'render function'、'v-on handler'、'watcher getter' 等</p><pre class="brush:php;toolbar:false;"> // ✅ 可以返回 false 阻止错误继续向上冒泡
// return false
// ❌ 不要在此处 throw 新错误,否则可能引发无限循环或白屏
})
return {}} }
参数说明:
- error:抛出的 Error 实例;
- instance:发生错误的子孙组件的组件实例(非当前组件),可用于访问其 props、slots、emit 等;
-
info:字符串,标识错误来源上下文,常见值:
render function、v-on handler、watcher getter、watcher callback、mounted hook等。
关键注意事项
- 仅对未被捕获的错误生效:如果子组件自己用了 try/catch 或定义了 onErrorCaptured 并未阻止冒泡(即没返回 false),错误才会上浮到父级;
-
不能捕获异步错误(如 setTimeout、fetch.then)中的未处理 Promise rejection,除非你在 Promise 链中显式 reject 并未 catch —— 此类错误需配合
window.addEventListener('unhandledrejection')全局监听; - 返回 false 可阻止错误继续向更上层传播,适合在布局容器、路由视图组件中做兜底处理(如显示错误提示、重置状态),避免整个应用崩溃;
- 慎用于业务逻辑处理:它本质是错误边界(error boundary)机制,不是常规错误处理手段,不应替代 try/catch 或请求异常判断;
- 在
script setup语法糖中同样可用:onErrorCaptured(() => {...}),无需额外 import(已自动引入)。
典型使用场景示例
比如你有一个 <dashboardlayout></dashboardlayout> 组件,里面用 <slot></slot> 渲染不同业务模块(如 UserList、OrderChart)。某个模块因 API 数据结构变更突然报错:
<!-- DashboardLayout.vue -->
<template><div class="layout">
<header>仪表盘</header><main><slot></slot></main>
</div>
</template><p><script setup>
import { onErrorCaptured } from 'vue'</script></p><p>onErrorCaptured((err) => {
// 记录错误 + 提示用户 + 自动降级展示空白卡片
console.error('[Layout] 子模块异常:', err)
alert('当前模块加载异常,请稍后重试')
return false // 阻止错误影响整个页面
})
</p>
这样即使 UserList 内部渲染时报错,页面也不会白屏,而是保留在 Layout 结构中给出友好反馈。










