Skip to content

vue之api-生命周期钩子errorCaptured(Vue2.x)和onErrorCaptured(Vue3.x)

1、认识

👉 errorCaptured(Vue2.5+版本新增)

vue之中的生命周期钩子,用于捕获子组件中的错误。它在组件树中向上冒泡,允许父组件处理子组件抛出的错误。

👉 onErrorCaptured(Vue3.x版本)

在Vue3.x版本中,errorCaptured被重命名为onErrorCaptured

errorCaptured在vue2.5以后的版本之中才有!!!

☞ 介绍

简单概括一下就是可以拿来给我们捕获错误,给用户提示用户信息,然后防止程序崩溃!

☞ 语法

errorCaptured返回一个布尔值(true|false)

true => 错误将不会继续向上传递,相当于它拦截了

false=> 错误继续传播

☞ 使用

比如我们在父组件之中使用了一个子组件ChildComponent,这个时候想要捕获这个组件的错误,然后再父组件进行提示就可以用到errorCaptured

2、errorCaptured-vue2使用

☞ 使用

JS
<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script>
export default {
  errorCaptured(err, vm, info) {
    // 处理错误
    console.error('捕获到的错误:', err);
    // 可以返回 true 来阻止向上冒泡
    return false;
  }
};
</script>

需要额外注意的就是:errorCaptured 只捕获子组件错误,不能捕获父组件错误。

3、onErrorCaptured-vue3使用

☞参数说明

err:捕获到的错误对象。

instance:发生错误的组件实例。

info:包含错误发生位置的附加信息,例如 onErrorCaptured 钩子的调用栈

父组件

JS
<template>
  <div>
    <ChildComponent />
  </div>
</template>

<script>
import { defineComponent, onErrorCaptured } from 'vue';

export default defineComponent({
  setup() {
    onErrorCaptured((err, instance, info) => {
      console.error('捕获到的错误:', err);
      console.log('错误发生在组件:', instance);
      console.log('错误信息:', info);
      // 返回 true 阻止错误继续向上传递
      return false; // 可以选择继续传播错误
    });
  }
});
</script>

子组件

在组件抛出错误给父组件,让他处理

JS
<template>
  <div>
    <button @click="throwError">抛出错误</button>
  </div>
</template>

<script>
import { defineComponent } from 'vue';

export default defineComponent({
  setup() {
    const throwError = () => {
      throw new Error('这是一个错误');
    };
    return { throwError };
  }
});
</script>

4、onErrorCaptured源码

之前有个朋友问我为什么只有vue3-onErrorCaptured的手写原理,但是却没有vue2-errorCaptured的手写原理,因为毕竟精力有限,而且官方不维护Vue2,所以深度的研究Vue2已经没有太大的左右,所以只是研究Vue3 之中源码的原理。

☞ 接下来我们就看一下 onErrorCaptured源码,方便我们进行理解

onErrorCaptured 机制比我们之前写的其他的部分都要简单的多

onErrorCaptured主要传入三个参数:(错误、组件实例、错误信息)

JS

// 自定义 error captured 逻辑
const onErrorCaptured = (err, instance, info) => {
  console.error('手动捕获的错误:', err);
  console.log('发生错误的组件实例:', instance);
  console.log('错误信息:', info);
  // 返回 false 表示错误未被处理
  return false;
};

//使用的时候
 onErrorCaptured(new Error('Simulated Error'), null, 'child component');

☞ 接下来我们手写一个简化版的框架使用 onErrorCaptured,然后尝试一下使用onErrorCaptured,这部分学习起来有些晦涩,也可以跳过这部分的理解暂时

  • 基本结构

这里面其实是模拟了一下Vue的Component组件,整个过程:

addChild()添加子组件

render()渲染组件

返回创建组件

渲染父组件

渲染子组件

拿到父组件中的onErrorCaptured钩子抛出的错误(错误来自于子组件)

JS
class Component {
  constructor(options) {
    this.options = options;
    this.parent = null;
    this.children = [];
  }

  // 添加子组件
  addChild(child) {
    this.children.push(child);
    child.parent = this;
  }

  // 渲染组件
  render() {
    if (this.options.render) {
      try {
        this.options.render();
      } catch (err) {
        // 捕获错误并处理
        if (this.options.onErrorCaptured) {
          // 如果父组件定义了 onErrorCaptured 钩子,就调用它
          const handled = this.options.onErrorCaptured(err, this, 'render');
          if (!handled) {
            // 如果错误没有被处理,继续向上抛出
            if (this.parent) {
              this.parent.render();
            } else {
              console.error('Unhandled error:', err);
            }
          }
        } else {
          console.error('Error caught in render:', err);
        }
      }
    }
    // 递归渲染子组件
    this.children.forEach(child => child.render());
  }
}

function createComponent(options) {
  return new Component(options);
}

// 模拟 Vue 的 `onErrorCaptured` 行为
  • 示例组件
JS
// 父组件
const ParentComponent = createComponent({
  render() {
    console.log('Parent render');
    // 假设子组件抛出错误
    childComponent.render();
  },
  onErrorCaptured(err, instance, info) {
    console.log('捕获到错误:', err);
    console.log('发生错误的组件:', instance);
    console.log('错误信息:', info);
    // 处理错误并阻止错误继续传播
    return true; // 返回 true,表示错误已处理
  }
});

// 子组件
const childComponent = createComponent({
  render() {
    console.log('Child render');
    // 抛出一个错误
    throw new Error('Child component error!');
  }
});

// 将子组件添加到父组件
ParentComponent.addChild(childComponent);

// 渲染父组件
ParentComponent.render();

Released under the MIT License.