Vue3项目中如何捕获不同层级的异常/错误?

228 阅读2分钟

项目中如果没有对异常做处理,可能导致应用崩溃或显示报错信息影响用户体验。因此需要对不同层级的错误进行捕获,确保用户即使在错误发生时仍能使用应用的其他功能或者能查看到更友好的提示消息。

组件级异常捕获:

  1. 单组件 使用 errorCaptured 钩子来捕获单一组件中的错误。
<template>
 <button @click="test">抛出错误</button>
</template>
<script setup lang="ts">
const test = () => {
  throw 'error'
}
onErrorCaptured((err, instance, info)=>{
  console.log('错误:',err, instance, info)
})
</script>
  1. 多组件(跨多个组件的错误边界

使用方式:

// index.vue
<template>
   <ErrorBoundary>
      <router-view v-slot="{ Component, route }">
        <template v-if="Component">
          <component :is="Component" :key="route.name" />
        </template>
      </router-view>
    </ErrorBoundary>
</template>
<script setup lang="ts">
import ErrorBoundary from "@/components/error/ErrorBoundary.vue";
</script>

实现方式:

// 404.vue
<template>
  <el-result
    status="404"
    title="404"
    sub-title="Sorry, the page you visited does not exist."
  >
    <template #extra>
      <a-button type="primary" @click="onChange"> 回到首页 </a-button>
    </template>
  </el-result>
</template>
<script lang="ts">
export default {
  name: "NotFound",
};
</script>
<script lang="ts" setup>
import { defineEmits } from "vue";
const emit = defineEmits(["change"]);
const onChange = () => {
  emit("change", false);
};
</script>

// ErrorBoundary.vue
<template>
  <div v-if="isError">
    <NotFound @change="handleErrorChange" />
    </div>
  <div v-else>
    <slot></slot>
  </div>
</template>
<script setup lang="ts">
import router from "@/router";
import NotFound from "@/components/error/404.vue";
import { onErrorCaptured, ref } from "vue";
const isError = ref(false);
onErrorCaptured((err, vm, info) => {
  console.error(
    "[捕获错误]",
    err.message,
    "vm",
    vm,
    "info",
    info,
    window.history
  );
  isError.value = true;
  return false; // onErrorCaptured 早于window.onerror 等执行,这里捕获了返回false就不会向上继续抛出了
});

const handleErrorChange = (isError: boolean) => {
  if (!isError) {
    // 在这里进行错误处理
    // router.push("/").then(() => {
    //   location.reload();
    // });
  }
};
</script>

全局异常捕获

  1. 使用 app.config.errorHandler 设置全局错误处理器来捕获未通过组件级别捕获的错误。
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
    // 这里可以执行全局的错误处理逻辑,比如上报服务器
    console.error('Global error handler:', err, { instance, info });
  };
  1. 通过window事件捕获 可以添加全局的 window 事件来捕获未处理的错误和未捕获的 Promise 异常。
window.addEventListener(
  "error",
  (e) => {
    console.log("全局报错捕获", e);
    return true;
  },
  true
);

// 处理未捕获的异常,主要是promise内部异常,统一抛给 onerror
window.addEventListener("unhandledrejection", (e) => {
  throw e.reason;
});

代码级局部捕获

使用 try-catch 捕获异步或特定代码块中的错误。

const fetchData = async () => {
   try {
     const response = await fetch('https://api.example.com/data');
     result.value = await response.json();
   } catch (error) {
     console.error('Error fetching data:', error);
     // 局部错误处理逻辑
   }
};

总结

通过以上几种方法,可以在 Vue 3 项目中可以有效地捕获和处理不同层级的错误,从而提升用户体验。