动态路由

如果有很多遵循相同格式的数据,例如用户列表或消息列表,并且需要为每个数据创建一个页面,我们需要使用路由模式。 通过路由模式,我们可以根据一些附加信息从同一组件动态创建新路由。 例如,我们希望为每个用户呈现用户视图组件,但具有不同的 id 值。 Vue Router 为我们提供了使用冒号(:)表示的动态段来实现动态路由的能力。

我们不使用在刷新时保留其值或出现在 URL 中的参数(params),而是直接在路径中定义所需的参数,如下所示:

{
    path: '/user/:id',
    name: 'user',
    component: () => import(/* webpackChunkName: "user" */ '../views/User.vue')
}

在上面的代码中,:id 表示这里的参数不是静态的。 当路由与给定模式匹配时,Vue Router 将使用适当的内容渲染相应的组件,同时保持 URL 应有的样子。 并且 :id 的值将在该视图组件的实例中公开为 $route.params.id

<template>
    <div>
        <h1>About a user: {{$route.params.id}}</h1>
    </div>
</template>

当用户选择 /user/1 和 /user/2 (./src/App.vue) 等 URL 时,Vue 将使用我们的模板自动生成子页面。

导航路径将映射到相同的路由模式和组件,但具有不同的信息,如以下屏幕截图所示:

image 2023 10 14 23 07 13 589
Figure 1. Figure 6.32: Navigate to /user/2

当您单击用户 1 时,您将看到以下内容:

image 2023 10 14 23 08 25 253
Figure 2. Figure 6.33: Navigate to /user/1

我们还可以使用 props: true 将 id 规范化为 User 组件的 props,并将其与 beforeRouteEnter() 结合起来,以在创建和渲染实例之前加载所选用户的数据:

<script>
import users from '../assets/users.js';

export default {
    props: {
        id: Number
    },
    data() {
        return {
            name: '',
            age: 0
        }
    },
    beforeRouteEnter(to, from, next) {
        next(vm => {
            const user = users[vm.id];
            vm.name = user.name;
            vm.age = user.age;
        })
    }
}
</script>

现在我们可以调整 <template> 来打印用户的详细信息:

<template>
    <div>
        <h1>About a user: {{$route.params.id}}</h1>
        <h2>Name: {{name}}</h2>
        <p>Age: {{age}}</p>
    </div>
</template>

选择 /user/1 时的输出现在如下:

image 2023 10 14 23 12 26 832
Figure 3. Figure 6.34: Navigate to /user/1 with updated UI

如果我们在 user/:id 路由中并将 :id 更改为另一个用户,我们需要相应地更新本地数据,因为在这种情况下 beforeRouteEnter 不会再次被触发。事实上,组件的所有生命周期 Hook 都不会被调用,因为组件实例没有被重新创建:

beforeRouteUpdate(to, from, next) {
    const user = users[to.params.id - 1];
    this.name = user.name;
    this.age = user.age;
    next();
}

在本节中,我们通过设置从给定 URL 中提取参数的路由来了解动态路由。该技术允许您创建用户友好的 URL 并将信息动态传递给路由。在下一节中,我们将研究捕获错误路径。

捕获错误路径

除了主页(“/”)之外,我们始终需要记住处理的其它重要路由包括错误路由,例如当 URL 路径与任何注册路径不匹配时出现 404 Not found 等。

对于 404 Not found,我们可以使用正则表达式星号 *,它代表匹配所有内容来收集所有与路由不匹配的情况。 该路由器的配置应位于数组路由的末尾,以避免匹配错误的路径:

{
    path: '*',
    name: '404',
    component: () => import(/* webpackChunkName: "404" */ '../views/404.vue'),
}

当我们输入错误的 /users 路径时,输出将如下:

image 2023 10 14 23 17 13 948
Figure 4. Figure 6.35: Redirect to 404 when the '/users' path is not found

在本节中,我们了解了如何使用 * 正则表达式通配符创建一个包罗万象的 404 页面,向导航到不存在的路由的任何人显示。 接下来,我们将实现一个消息路由,使用动态路由模式在 URL 本身中传递相关数据。

练习 6.05:使用动态路由模式为每条消息实现消息路由

回到练习 6.04 中的消息源,将消息列表提取到外部文件并仅在查看 MessageFeed 时加载,我们将重构消息路径,以使用路由模式根据用户的选择动态导航到特定消息路径。 这将使您熟悉与其它导航 Hook 结合创建和维护动态路由。

要访问本练习的代码文件,请参阅 https://packt.live/32sWogX

  1. 让我们打开 ./src/router/index.js 并将消息路由的路径配置更改为 /message/:id,其中 id 将是该消息在消息列表中的索引:

    {
        path: '/message/:id',
        name: 'message',
        component: () => import(/* webpackChunkName: "message" */'../views/Message.vue'),
        props: true,
    }
  2. 现在导航到 ./src/views/MessageFeed.vue 并将每条消息的 router-link 的 to 属性更改为以下内容:

    <router-link :to="`/message/${i}`">
  3. 让我们回到 ./src/router/index.js 并将 beforeEnter 定义为异步 Hook,用于将消息内容延迟加载到 Message 组件的 content 属性中:

    async beforeEnter(to, from, next) {
        if (to.params && to.params.id) {
            const id = to.params.id;
            const { module } = await import (/* webpackChunkName: "messagesFeed" */ '../assets/messages.js');
            const messages = module.default;
            if (messages && messages.length > 0 && id < messages.length) {
                to.params.content = messages[id];
            }
        }
        next()
    },
  4. 使用以下命令运行应用程序:

    yarn serve

    当点击消息源中的第一条消息时,下一页将如下所示:

    image 2023 10 15 08 03 50 609
    Figure 5. Figure 6.36: The page displayed when visiting the /message/0 path

现在您已经了解了如何使用动态路由,您可以进一步尝试更多层的路由模式,例如 message/:id/author/:aid。然而,对于这种情况,我们通常使用更好的方法,即嵌套路由。