Vue 3 全局错误捕获需分层配置:一、用 app.config.errorHandler 捕获 Vue 运行时错误;二、用 window.onerror 和 unhandledrejection 补齐 JS 全局与 Promise 错误;三、封装统一上报接口并携带上下文;四、可选使用 errorCaptured 做组件级降级。

Vue 3 项目初始化阶段就配置好全局错误捕获机制,能避免后期补漏、重复 try/catch,也能确保线上错误“不丢失、可定位、能上报”。核心不是堆功能,而是分层收口:用 app.config.errorHandler 捕获 Vue 运行时错误,再叠加原生监听覆盖盲区,最后统一走日志上报逻辑。
一、主通道:配置 app.config.errorHandler(Vue 层错误兜底)
这是 Vue 自身错误的唯一官方入口,覆盖组件渲染、生命周期钩子、setup 函数、事件处理器、watch、过渡钩子等同步/异步(非 Promise)错误。
- 在
main.js或应用初始化文件中设置,必须在app.mount()之前 - 接收三个参数:
err(Error 实例)、instance(出错组件实例,可为 null)、info(字符串,如"render function"或"mounted hook") - 开发环境建议保留
console.error辅助调试;生产环境应关闭控制台输出,只执行上报 - 注意:不要在 handler 内直接修改响应式状态(如
ref.value = xxx),可能触发响应式系统冲突;如需更新 UI,用nextTick包裹
示例代码:
import { createApp } from 'vue'
import { nextTick } from 'vue'
import App from './App.vue'
import { postErrorLogs } from '@/api/commonApi'
const app = createApp(App)
app.config.errorHandler = (err, instance, info) => {
// 生产环境才上报
if (import.meta.env.PROD) {
postErrorLogs({
message: err.message,
stack: err.stack,
info,
component: instance?.type?.name || 'unknown',
url: window.location.href
})
}
// 开发环境仍打印便于调试
if (!import.meta.env.PROD) {
console.error('[Vue Error]', err, instance, info)
}
}
app.mount('#app')
二、补盲区:补充 window.onerror 和 unhandledrejection
errorHandler 不处理以下三类错误,必须手动监听:
-
JS 全局同步错误(如顶层脚本语法错误、
setTimeout中抛出未捕获异常)→ 用window.onerror -
未 catch 的 Promise 拒绝(如 API 请求失败但没写
.catch)→ 用window.addEventListener('unhandledrejection') -
静态资源加载失败(如图片 404、CSS 加载失败)→ 单独为
<img>等加@error或全局监听document.addEventListener('error', ...),但通常优先关注前两类
推荐统一格式化后调用同一上报函数(如上面的 postErrorLogs),保持字段一致:
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
// main.js 中继续追加
if (import.meta.env.PROD) {
window.onerror = (message, source, lineno, colno, error) => {
postErrorLogs({
message: error?.message || message,
stack: error?.stack,
source,
lineno,
colno,
errorType: 'js-error',
url: window.location.href
})
}
window.addEventListener('unhandledrejection', (event) => {
const reason = event.reason
postErrorLogs({
message: reason?.message || 'Unhandled promise rejection',
stack: reason?.stack,
errorType: 'promise-reject',
url: window.location.href
})
})
}
三、封装错误上报接口(轻量实用版)
上报接口建议独立封装,自动携带环境、终端类型、用户 ID(如有)、页面路径等上下文,避免每个监听里重复拼参。
- 判断是否为生产环境,非生产直接 return
- 读取 Vuex/Pinia store 中的用户信息(若已登录),或 fallback 为空字符串
- 识别终端类型(Android/iOS/Web),便于后续按端分析
- 使用
fetch或axios上报,建议加简单防抖(如 1 秒内相同错误只报一次),避免刷屏
参考结构(src/api/commonApi.js):
import store from '@/store'
const osType = () => {
const ua = navigator.userAgent
if (/Android/.test(ua)) return 1
if (/iPhone|iPad/.test(ua)) return 2
return 3
}
export function postErrorLogs(params) {
if (!import.meta.env.PROD) return Promise.resolve()
const data = {
...params,
project: 'your-project-name',
terminal: osType(),
pageUrl: window.location.href,
userInfo: store.getters['User/getUserInfo']?.userId || ''
}
return fetch('/api/common/log/error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
}
四、可选增强:组件级 errorCaptured 做 UI 降级
如果某些区域(如第三方图表、动态表单)容易出错且影响主流程,可在父组件用 errorCaptured 主动拦截,返回 false 阻止冒泡,并切换 fallback UI:
<template><div>
<childcomponent v-if="!hasError"></childcomponent><div v-else class="error-fallback">内容加载失败,请重试</div>
</div>
</template><script setup>
import { ref } from 'vue'
import { onErrorCaptured } from 'vue'
const hasError = ref(false)
onErrorCaptured((err, instance, info) => {
console.warn('子组件错误被捕获:', err.message, info)
hasError.value = true
return false // 阻止向上传播到全局 errorHandler
})
</script>
注意:它只捕获子组件同步错误,不捕获异步回调或事件处理器内错误,不能替代全局机制,而是作为精准防御补充。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










