Vue3实战:使用 errorHandler 捕获全局错误

news2024/9/20 23:32:02

你好同学,我是沐爸,欢迎点赞、收藏、评论和关注。

在 Vue3 中,app.config.errorHandler 是一个错误处理器,用于为应用内抛出的未捕获错误指定一个全局处理函数,它接收三个参数:错误对象、触发该错误的组件实例和一个指出错误来源类型信息的字符串。

app.config.errorHandler = (err, instance, info) => {
  // 处理错误,例如:报告给一个服务
}

一、错误来源

它可以从下面这些来源中捕获错误:

  • 组件渲染器
  • 事件处理器
  • 生命周期钩子
  • setup() 函数
  • 侦听器
  • 自定义指令钩子
  • 过渡 (Transition) 钩子

二、错误捕获

1.启用 errorHandler,接收返回的参数,调用接口。

main.js

import { createApp } from 'vue'
import App from './App.vue'
import axios from 'axios'

const app = createApp(App)

app.config.errorHandler = (error, instance, info) => {
  axios.post('/api/error', {
    message: error.message,
    type: info
  }).then(() => {
    console.log('success')
  })
}

app.mount('#app')

第一个参数 error 是一个错误对象,包含错误的详细信息,error.message 则是一个简短的错误描述,向后台提交错误信息时 error.message 更适合。instance 组件实例,一般用不到。

2.安装 axios,并设置接口代理。

vite.config.js

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
    }
  }
})

3.启动一个后台服务,以 Node.js 的 Express 为例

npm init -y
npm install express

创建 index.js,并输入以下内容:


const express = require('express')
const fs = require('fs')
const app = express()
app.use(express.json())

app.post('/api/error', (req, res) => {
    const { message, type } = req.body
    fs.appendFile('./error.txt', `${message} - ${type} \n`, (error, data) => {
        if (error) {
            console.log(error)
            return
        }

        res.send({
            code: 8200,
            success: true
        })
    })
})

app.listen(3000, () => {
  console.log('Server started on port 3000')
})

启动服务,控制台执行 node index.js,这样后台服务就启动好了。

4.当页面有报错并调用后台接口会,就会往后台的 error.txt 文件中插入一条数据。

count.value.split is not a function - transition hook 
count.value.split is not a function - transition hook 
fn is not defined - watcher callback 
fn is not defined - watcher callback 
abc is not defined - setup function 
abc is not defined - setup function 
abc is not defined - setup function 
abc is not defined - setup function 
count.value.split is not a function - mounted hook 
count.value.split is not a function - setup function 
abc is not defined - setup function 
count.value.split is not a function - setup function 
count.value.split is not a function - mounted hook 
count.value.split is not a function - mounted hook 
count.value.split is not a function - setup function 
count.value.split is not a function - mounted hook 
count.value.split is not a function - setup function 

三、示例

1.组件渲染器错误

<script setup>
import { ref } from 'vue'
const count = ref(100)
</script>

<template>
    <div>
        <!-- render function -->
        <p>{{ count.split('') }}</p>
    </div>
</template>

因为 count 是数字,并不具有 split 方法,所有组件渲染会报错,app.config.errorHandler 中的 info 参数的返回结果为 render function

2.事件处理器错误

指在组件的事件处理方法中产生的错误,app.config.errorHandler 中的 info 参数的返回结果为 native event handler

<script setup>
import { ref } from 'vue'

const count = ref(100)

function handleClick() {
    // count.value.split('') // 不存在的属性
    // fn() // 不存在的方法
    // console.log(abc) // 不存在的变量
    // throw new Error('报错了') // 主动抛出的错误
}
</script>

<template>
    <div>
        <p>{{ count }}</p>
        <button @click="handleClick">点击</button>
    </div>
</template>

3.生命周期钩子

指在生命周期钩子中产生的错误,app.config.errorHandler 中的 info 参数的返回结果为钩子名+ hook,如 mounted hook

<script setup>
import { ref, onMounted } from 'vue'

const count = ref(100)

onMounted(() => {
  // count.value.split('') // 不存在的属性
  // fn() // 不存在的方法
  // console.log(abc) // 不存在的变量
  // throw new Error('报错了') // 主动抛出的错误
})
</script>

<template>
    <div>
        <p>{{ count }}</p>
    </div>
</template>

4.setup 函数

指在 <script setup>setup()中产生的错误,app.config.errorHandler 中的 info 参数的返回结果为 setup function

<script setup>

<script setup>
import { ref, onMounted } from 'vue'

const count = ref(100)

// count.value.split('') // 不存在的属性
// fn() // 不存在的方法
// console.log(abc) // 不存在的变量
// throw new Error('报错了') // 主动抛出的错误

// 监听不存在的 abc,这里也是 setup 错误
watch(abc, (newValue) => {
    console.log(newValue)
})
</script>

<template>
    <div>
        <p>{{ count }}</p>
    </div>
</template>

setup()

<template>
  <div>
    <p>{{ count }}</p>
  </div>
</template>

<script>
  import { ref } from 'vue'
  export default {
    setup() {
      const count = ref(100)
      count.value.split('')
      // fn()
      // console.log(abc)
      // throw new Error('报错了')
    }
  }
</script>

5.侦听器错误

指在 watchwatchEffect 回调中产生的错误,初始化监听产生的错误属于 setup function错误,app.config.errorHandler 中的 info 参数的返回结果为 watcher callback

watch

<script setup>
import { ref, watch } from 'vue'

const count = ref(100)

watch(count, (newValue) => {
    // count.value.split('')
    // fn()
    // console.log(abc)
    // throw new Error('报错了')
})
</script>

<template>
    <div>
        <p>{{ count }}</p>
    </div>
</template>

watchEffect

<script setup>
import { ref, watchEffect } from 'vue'

const count = ref(100)

watchEffect(() => {
    // count.value.split('')
    // fn()
    // console.log(abc)
    // throw new Error('报错了')
})
</script>

<template>
    <div>
        <p>{{ count }}</p>
    </div>
</template>

6.自定义指令钩子错误

指在自定义指令钩子中产生的错误,app.config.errorHandler 中的 info 参数的返回结果为 directive hook

<script setup>
// 添加不存在的属性,不会导致报错
const vColor = {
    abc: 'abc', // 不会报错
    mounted: el => {
        el.style.color = 'red'
        // count.value.split('')
        // fn()
        // console.log(abc)
        // throw new Error('报错了')
    }
}

</script>

<template>
    <div>
        <p v-color>hello</p>
    </div>
</template>

7.过渡 (Transition) 钩子错误

在使用 Transition 的钩子时产生的错误,app.config.errorHandler 中的 info 参数的返回结果为 transition hook

以 onEnter 为例:

<script setup>
import { ref } from 'vue'

const count = ref(100)
const show = ref(false)

function handleClick() {
  show.value = !show.value
}

function onEnter(el, done) {
    el.style.color = 'blue'
    done()
  
    // count.value.split('')
    // fn()
    // console.log(abc)
    // throw new Error('报错了')
}
</script>

<template>
    <div>
        <button @click="handleClick">点击</button>

        <Transition @enter="onEnter">
            <p v-if="show">内容</p>
        </Transition>
    </div>
</template>

四、errorCaptured / onErrorCaptured()

两者作用相同,errorCaptured用于选项式API,onErrorCaptured() 用于组合式API,都为组件中的一个钩子,作用是在捕获了后代组件传递的错误时调用。

错误传递规则

  • 如果组件的继承链或组件链上存在多个 errorCaptured 钩子,对于同一个错误,这些钩子会被按从底至上的顺序一一调用。这个过程被称为“向上传递”,类似于原生 DOM 事件的冒泡机制。
  • 如果 errorCaptured 钩子本身抛出了一个错误,那么这个错误和原来捕获到的错误都将被发送到 app.config.errorHandler
  • errorCaptured 钩子可以通过返回 false 来阻止错误继续向上传递。即表示“这个错误已经被处理了,应当被忽略”,它将阻止其他的 errorCaptured 钩子或 app.config.errorHandler 因这个错误而被调用。

1.向上传递

main.js 中 app.config.errorHandler 方法不变。

Parent.vue

<script setup>
import { onErrorCaptured } from 'vue'
import Child from './Child.vue'

onErrorCaptured((error, instance, info) => {
    console.log('from Child', error, instance, info)
})
</script>

<template>
    <Child></Child>
</template>

Child.vue

<script setup>
import { onErrorCaptured } from 'vue'
import GrandChild from './GrandChild.vue'

onErrorCaptured((error, instance, info) => {
    console.log('from GrandChild', error, instance, info)
})
</script>

<template>
    <GrandChild></GrandChild>
</template>

GrandChild.vue

<script setup>
console.log(abc)

// 这里不会起作用,因为 onErrorCaptured 监听来自后代组件的错误
onErrorCaptured((error, instance, info) => {
    console.log('from GrandChild', error, instance, info)
})
</script>

<template>
    <p>hello world</p>
</template>

以上代码执行后,会以此触发 Child.vue 和 Parent.vue 中的 onErrorCaptured钩子,最后触发 app.config.errorHandler 中的回调。

2.阻止传递

如果在 Child.vue 的 onErrorCaptured 中添加 return false,那么Parent.vue 和 app.config.errorHandler 中将不会收到错误,因为 Child.vue 组织了错误的传递。

3.抛出错误

如果 Child.vue 组件的onErrorCaptured钩子中抛出了错误,那么来自 GrandChild.vue 和 Child.vue 自身的错误都会向上传递,这意味着 Parent.vue 和 app.config.errorHandler 都会收到这两个错误。

Child.vue

<script setup>
import { onErrorCaptured } from 'vue'
import GrandChild from './GrandChild.vue'

onErrorCaptured((error, instance, info) => {
    console.log(def)
    // console.log('from GrandChild', error, instance, info)
    // return false
})
</script>

<template>
    <GrandChild></GrandChild>
</template>


好了,分享结束,谢谢点赞,下期再见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一起对话式学习-机器学习03——模型评估与模型选择

【一】前言 这一部分其实已在第二节中介绍到&#xff0c;这节起到回顾归纳的作用。 【二】训练误差与测试误差 首先&#xff0c;在分类问题中&#xff0c;有误差率和准确率两个概念&#xff0c;二者和为1。 误差率&#xff1a;分类错误的样本数占总数的比例。 其次&#xff0c…

数仓工具:datax

datax可以理解为sqoop的优化版&#xff0c; 速度比sqoop快 因为sqoop底层是map任务&#xff0c;而datax底层是基于内存 DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定…

4款音频转文字在线转换工具帮你解锁新的记录模式。

越来越多的人都知道使用一些工具来将音频直接转换成文字&#xff0c;这样便省去了手动输入的麻烦。而且使用音频进行记录也能够提高工作的效率&#xff0c;像会议记录&#xff0c;课堂教学记录&#xff0c;采访录音等。如果大家有需要将自己的音频转成文字&#xff0c;可以试试…

PDF——压缩大小的方法

方法一&#xff1a;QQ浏览器->格式转换->PDF转纯图PDF

【C++】STL----stack和queue常见用法

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;C从小白到高手 &#x1f339;往期回顾&#x1f339;&#xff1a;【C】list常见用法 &#x1f516; 流水不争&#xff0c;争的是滔滔不息。 文章目录 一、stack的介绍s…

KTH7823——16 位高精度低延时霍尔磁编码器可编程 ABZ 和 PWM 输出模式角度传感器

KTH7823 是一款高精度绝对角度霍尔传感器芯片&#xff0c;最高 16 位分辨率绝对角度输出&#xff0c;可 实现在轴向和离轴场合下的无接触式磁场角度测量。不论转速范围在 0-120000rpm 之间&#xff0c; KTH7823 都能快速准确地输出角度信息&#xff0c;适用于需要精准角…

7个提升网站分页体验的 CSS 和 JavaScript 代码片段

文章目录 前言正文1.简洁直观的悬停分页效果2.实时显示页码的分页3.适合响应式设计的多功能分页4.专为移动设备优化的分页5.无数字的极简分页设计6.触屏友好的分页7.结合无限滚动与分页的设计 总结 前言 分页是内容丰富的网站中不可缺少的导航工具&#xff0c;能帮助用户更轻松…

鱼类计数与识别系统源码分享

鱼类计数与识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

【C语言】⾃定义类型:联合和枚举

⾃定义类型&#xff1a;联合和枚举 1. 联合体1.1 联合体类型的声明1.2 联合体的特点1.3 相同成员的结构体和联合体对⽐1.4 联合体⼤⼩的计算1.5 联合的⼀个练习 2. 枚举类型2.1 枚举类型的声明2.2 枚举类型的优点2.3 枚举类型的使⽤ 1. 联合体 1.1 联合体类型的声明 像结构体…

滚珠花键与滚珠丝杆的区别与应用

在机械工业中&#xff0c;经常使用滚珠花键这种传动元件&#xff0c;人们经常拿它与滚珠丝杆相比较&#xff0c;甚至与之混淆。事实上&#xff0c;它们是不同的&#xff0c;滚珠花键和滚珠丝杆在机械传动领域中各有其独特的作用和特点。那么&#xff0c;两者之间的区别是什么呢…

list(二) (list模拟实现)

首先进行大框架 先写基本的结点类 有data next prev template<class T>class ListNode//或者使用struct 就不用在写public声明公有{public://这里不仅仅是成员函数 成员变量也要公有化 ListNode<T>* _next;ListNode<T>* _prev;T _data;}之后是链表list类…

OpenHarmony(鸿蒙南向开发)——小型系统内核(LiteOS-A)【时间管理】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 子系统开发内核 轻量系统内核&#xff08;LiteOS-M&#xff09; 轻量系统内核&#…

围剿Model Y,小米SUV也来拼刺刀了

文 | AUTO芯球 作者 | 雷慢 马斯克真是被小米雷军盯上了&#xff0c; 前面小米SU7死磕Model 3&#xff0c; 现在小米SUV又来打Model Y了&#xff0c; 别不信啊&#xff0c;就刚刚&#xff0c;小米SUV出现了最大的曝光&#xff0c; 外观谍照&#xff0c;内饰中控台都曝光了…

RflySim工具链常见问题答疑

1. RflySim结合硬件能不能实现无人机颜色巡线呢&#xff1f; 可以&#xff0c;内置有一个通过相机识别来攻击小球的实验&#xff0c;可见&#xff1a;【RflySim安装路径】\RflySimAPIs\8.RflySimVision\1.BasicExps\1-VisionCtrlDemos\e3_ShootBall&#xff0c;不过要想实现无人…

Linux 进程3

进程地址空间 CPU读取数据都需要地址&#xff0c;在计算机中所有东西都是一种数据&#xff0c;包括我们的进程。 这是一个进程空间示意图&#xff0c;操作系统通过task_struct结构体链表来管理每一个进程&#xff0c;结构体里面有一个指针指向操作系统为进程开辟的一段空间&am…

博导团队指导、解读实验结果、SCI论文润色

表观组&#xff1a; DAP-seq:转录因子-DNA互作研究工具 ATAC-seq :染色质开放程度研究工具 H3K4me3 ChIP-seq:组蛋白甲基化修饰工具 BS-seq :DNA甲基化研究工具 H3K27ac ChIP-seq:组蛋白乙酰化修饰研究工具 Cut&Tag:转录因子研究工具 ChIP-seq:转录因子-DNA互作工具 互作组…

HTTP 教程

HTTP/HTTPS 简介 HTTP&#xff08;Hypertext Transfer Protocol&#xff0c;超文本传输协议&#xff09;和 HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff0c;超文本传输安全协议&#xff09;是用于在网络中传输信息的两种主要协议。它们定义了客户端和服务器…

PDF样本册如何分享到朋友圈

​想象一下&#xff0c;你刚刚参加了一场行业盛会&#xff0c;获取了一份包含最新行业动态、优秀案例的PDF样本册。你迫不及待地想要分享给身边的朋友&#xff0c;与他们共同学习、探讨。然而&#xff0c;传统的分享方式要么依赖纸质版&#xff0c;要么通过电子邮件&#xff0c…

C++模拟实现list:list、list类的初始化和尾插、list的迭代器的基本实现、list的完整实现、测试、整个list类等的介绍

文章目录 前言一、list二、list类的初始化和尾插三、list的迭代器的基本实现四、list的完整实现五、测试六、整个list类总结 前言 C模拟实现list&#xff1a;list、list类的初始化和尾插、list的迭代器的基本实现、list的完整实现、测试、整个list类等的介绍 一、list list本…

LeetCode讲解篇之220. 存在重复元素 III

文章目录 题目描述题解思路题解代码 题目描述 题解思路 我们可以考虑存储数组中连续indexDiff个数字&#xff0c;这样我们只需要在这连续的indexDiff个数字中查找相差小于等于valueDiff的两个数字的问题 对于该查找问题&#xff0c;我们可以考虑使用以valueDiff大小为一个桶&a…