如何在为组件创建 props 时捕获路由错误

问题描述 投票:0回答:1

我试图捕获解析路由参数以传递给组件时可能发生的错误。例如,组件 A 需要一个

URL
对象,并且路由器在将其传递给组件之前从路由参数创建该对象,例如

{
  path: "/test/:parameter",
  name: "test",
  component: Test,
  props: (route) => ({
    url: new URL(route.params.parameter),
  }),
},

Vue Router 提供了 onError 函数来捕获某些类型的错误,并且 其他地方建议使用 Vue Router 的 beforeEach。不幸的是,如果在生成路由组件的 props 时抛出错误,这两种方法似乎都没有用。

onErrorv3 文档表明未涵盖此用例:

  • 错误在路由保护函数内同步抛出;
  • 通过在路由保护函数内调用 next(err) 来捕获并异步处理错误;
  • 尝试解析渲染路线所需的异步组件时发生错误。

但它并不完全清楚,如果这个用例没有被覆盖,它似乎也不是很有用。那么你会怎么做呢?

MCVE

我创建了一个最小示例来演示该行为。共有三个链接:

  1. “有效”-应该可以正常工作
  2. “无效” - 创建道具时抛出异常
  3. “不存在” - 应该抛出错误,因为路线不存在

“Invalid”肯定会引发未捕获的错误(如视图中所示),但 2. 和 3. 都不会按预期将日志消息写入控制台。

javascript vue.js vue-router
1个回答
0
投票

创建transformRoutes函数,您可以:

    beforeEach 中的
  1. parseProps,如果出错,创建一个
    error
    prop
  2. 在实际的
    props
    ' 调用中返回解析后的 props
  3. 如果 props 包含错误,则返回一些错误组件

(当然应该扩展它以处理所有可能的路由配置:

main.ts:

const router = createRouter({
  history: createWebHistory(),
  routes: transformRoutes([ routes here ])
});
import Error from './views/Error.vue';

export function transformRoutes(routes) {
    routes.forEach(route => {

        let _props, _component, props = {};

        [_props, route.props] = [route.props, () => {
            const out = props;
            props = {};
            return out;
        }];

        [_component, route.component] = [route.component, async () => {
            if (props.error) {
                return Error;
            }
            return _component;
        }];

        route.beforeEnter = (...args) => {
            try {
                props = _props(...args);
            } catch (e) {
                props = { error: e.message };
            }
        }
    });
    routes.children && transformRoutes(routes.children);
    return routes;
}

错误.vue:

<script setup>
defineProps({
  error: String,
});
</script>
<template>
  <div class="error">
    {{ error }}
    <div><button @click="$router.go(-1)">Go back</button></div>
  </div>
</template>
<style scoped>
.error {
  background: #fee;
  padding: 32px;
  border: 1px solid red;
  margin: 32px;
}
</style>
© www.soinside.com 2019 - 2024. All rights reserved.