经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
Vue 3 后端错误消息处理范例
来源:cnblogs  作者:开源博客  时间:2024/7/13 23:51:01  对本文有异议

1. 错误消息格式

前后端消息传递时,我们可以通过 json 的 errors 字段传递错误信息,一个比较好的格式范例为:

  1. {
  2. errors: {
  3. global: ["网络错误"],
  4. password: ["至少需要一个大写字母", "至少需要八位字符"]
  5. }
  6. }

errors 中,字段名代表出错位置(如果是输入框的话,对应错误要显示在框下面),内容为一个数组,每个字符串代表一个错误。

2. 处理函数

可以新建一个 composables 文件夹,以存储各个 components 中共用的逻辑,例如错误消息处理。这里在 composables 文件夹中新建一个 error.ts

  1. import { ref, type Ref } from 'vue';
  2. export interface ErrorFields {
  3. global: string[];
  4. [key: string]: string[];
  5. }
  6. export function useErrorFields(fields: string[]) {
  7. const errors: Ref<ErrorFields> = ref({ global: [], ...fields.reduce((acc, field) => ({ ...acc, [field]: [] }), {}) });
  8. const clearErrors = () => {
  9. for (const field in errors.value) {
  10. errors.value[field] = [];
  11. }
  12. };
  13. const hasErrors = (field?: string) => {
  14. if (field) {
  15. return errors.value[field].length > 0;
  16. }
  17. return Object.values(errors.value).some((field) => field.length > 0);
  18. };
  19. const addError = (field: string, message: string) => {
  20. if (field === '') {
  21. field = 'global';
  22. }
  23. const array = errors.value[field];
  24. if (!array.includes(message)) {
  25. array.push(message);
  26. }
  27. return array;
  28. };
  29. const removeError = (field: string, message?: string) => {
  30. if (field === '') {
  31. field = 'global';
  32. }
  33. if (message) {
  34. errors.value[field] = errors.value[field].filter((m) => m !== message);
  35. } else {
  36. errors.value[field] = [];
  37. }
  38. };
  39. return { errors, clearErrors, hasErrors, addError, removeError };
  40. }

这里我们就定义了错误类及其处理函数。

3. 组件中的使用

定义的 useErrorFields 工具可以在 component 中这样使用:

  1. <script setup lang="ts">
  2. import axios from 'axios';
  3. import { computed, onMounted, ref, type Ref } from 'vue';
  4. import { useErrorFields } from '@/composables/error';
  5. const { errors, clearErrors, addError, hasErrors } = useErrorFields(['username', 'password']);
  6. const username = ref('');
  7. function onSubmit() {
  8. const api = axios.create({
  9. baseURL: import.meta.env.VITE_API_URL,
  10. });
  11. api.get("/user/register")
  12. .catch((error) => {
  13. if (error.response && error.response.data && error.response.data.errors) {
  14. errors.value = { ...errors.value, ...error.response.data.errors };
  15. } else if (error.response) {
  16. addError('', '未知错误');
  17. } else {
  18. addError('', '网络错误');
  19. }
  20. })
  21. }
  22. </script>
  23. <template>
  24. <div
  25. v-if="hasErrors('global')"
  26. class="mb-5 rounded-md border-0 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-500 px-4 py-2"
  27. >
  28. <div class="flex text-red-700 dark:text-rose-400 space-x-2 mb-2">
  29. <p class="text-lg font-semibold">错误</p>
  30. </div>
  31. <ul class="flex flex-col font-medium tracking-wide text-sm list-disc pl-6">
  32. <li v-for="e in errors.global" v-html="e" />
  33. </ul>
  34. </div>
  35. <form>
  36. <div>
  37. <label for="username" class="block text-sm font-medium leading-6">
  38. 用户名
  39. <span class="text-red-700">*</span>
  40. </label>
  41. <div class="mt-2">
  42. <input
  43. v-model="username"
  44. @focus="clearErrors"
  45. id="username"
  46. name="username"
  47. type="text"
  48. autocomplete="username"
  49. required
  50. class="block w-full rounded-md border-0 py-1.5 px-3 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset focus:ring-indigo-600 focus:outline-none sm:text-sm sm:leading-6 dark:bg-white/10 dark:ring-white/20"
  51. :class="{ 'ring-red-500': hasErrors('username'), 'ring-gray-300': !hasErrors('username') }"
  52. />
  53. </div>
  54. <ul class="flex flex-col font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
  55. <li v-for="e in errors.username" v-html="e" />
  56. </ul>
  57. </div>
  58. <div>
  59. <button
  60. type="submit"
  61. class="flex w-full justify-center rounded-md px-3 py-1.5 text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 text-white shadow-sm hover:bg-indigo-500"
  62. :class="{
  63. 'cursor-default pointer-events-none': hasErrors() || processing,
  64. 'bg-gray-400': hasErrors(),
  65. 'bg-indigo-600': !hasErrors(),
  66. }"
  67. >
  68. 注册
  69. </button>
  70. </div>
  71. </form>
  72. </template>

接下来,我们一步步解析以上代码。

3.1 根据后端响应更新错误状态

我们首先使用 useErrorFields 定义了一个错误状态类:

  1. const { errors, clearErrors, addError, hasErrors } = useErrorFields(['username', 'password']);

这时候,错误状态 errors 中可访问三个字段,并将绑定到页面的不同位置:

global: 全局错误 / 无具体位置的错误 => 显示在表格顶端的单独框中

username: 用户名上的错误 => 显示在 username 输入框下方
password: 密码上的错误 => 显示在 password 输入框下方

接下来,我们需要定义提交函数,例如这里使用 axios 进行后端访问,后端地址用环境变量提供:

  1. function onSubmit() {
  2. const api = axios.create({
  3. baseURL: import.meta.env.VITE_API_URL,
  4. });
  5. api.get("/user/register")
  6. .catch((error) => {
  7. if (error.response && error.response.data && error.response.data.errors) {
  8. errors.value = { ...errors.value, ...error.response.data.errors };
  9. } else if (error.response) {
  10. addError('', '未知错误');
  11. } else {
  12. addError('', '网络错误');
  13. }
  14. })
  15. }

这样,后端返回错误信息时,错误状态会被自动更新。如果出现了网络错误或其他错误,addError类会在 global 字段上增加错误 (使用空字符串为第一个参数,默认添加到 global 字段)。

接下来,将错误状态绑定到页面。

3.2 绑定到输入框

  1. <input
  2. v-model="username"
  3. @focus="clearErrors"
  4. id="username"
  5. name="username"
  6. type="text"
  7. autocomplete="username"
  8. required
  9. class="block w-full rounded-md border-0 py-1.5 px-3 shadow-sm ring-1 ring-inset focus:ring-2 focus:ring-inset focus:ring-indigo-600 focus:outline-none sm:text-sm sm:leading-6 dark:bg-white/10 dark:ring-white/20"
  10. :class="{ 'ring-red-500': hasErrors('username'), 'ring-gray-300': !hasErrors('username') }"
  11. />

这里主要使用了两个个函数:

clearErrors: 当重新开始进行输入时,清除错误状态中的全部错误。

hasErrors: 当对应位置出现错误时,将输入框边框颜色变为红色。

将错误状态显示在输入框下:

  1. <div>
  2. <label for="username" class="block text-sm font-medium leading-6">
  3. 用户名
  4. <span class="text-red-700">*</span>
  5. </label>
  6. <div class="mt-2">
  7. <input
  8. ...
  9. />
  10. </div>
  11. <ul class="flex flex-col font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
  12. <li v-for="e in errors.username" v-html="e" />
  13. </ul>
  14. </div>

这里我们使用 <li> 标签,使用 errors.username 将对应位置的错误消息依次显示在输入框下。

3.4 全局消息显示在表格顶端

  1. <div
  2. v-if="hasErrors('global')"
  3. class="mb-5 rounded-md border-0 shadow-sm ring-1 ring-inset ring-gray-300 dark:ring-gray-500 px-4 py-2"
  4. >
  5. <div class="flex text-red-700 dark:text-rose-400 space-x-2 mb-2">
  6. <p class="text-lg font-semibold">错误</p>
  7. </div>
  8. <ul class="flex flex-col font-medium tracking-wide text-sm list-disc pl-6">
  9. <li v-for="e in errors.global" v-html="e" />
  10. </ul>
  11. </div>
  12. <form>
  13. ...
  14. </form>

这里使用 hasErrors('global') 来检测是否有全局错误,并在输入表顶端显示。

3.5 提交按钮在有错误时不允许点击

  1. <button
  2. type="submit"
  3. class="flex w-full justify-center rounded-md px-3 py-1.5 text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 text-white shadow-sm hover:bg-indigo-500"
  4. :class="{
  5. 'cursor-default pointer-events-none': hasErrors(),
  6. 'bg-gray-400': hasErrors(),
  7. 'bg-indigo-600': !hasErrors(),
  8. }"
  9. >
  10. 注册
  11. </button>

这里使用 hasErrors() 来检测错误状态类中是否有任何错误,并据此启用或禁用按钮。

4. 完整案例

如果你需要一个完整案例,这里有:错误状态处理在用户注册场景的案例,前端开源,详见:Github,你也可以访问 Githubstar.pro 来查看网页的效果(一个 Github 互赞平台,前端按本文方式进行错误处理)。

感谢阅读,如果本文对你有帮助,可以订阅我的博客,我将继续分享前后端全栈开发的相关实用经验。祝你开发愉快

原文链接:https://www.cnblogs.com/techhub/p/18301010/vue-error-handle

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号