将参数与 Props 解耦

在 index.js 文件中,让我们使用名为 props 的附加属性来调整 about 路由的配置。 通过将此属性的值设置为 true,路由器将自动理解 $route.params 并将其相应地映射到 props 组件中:

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

在 About.vue 文件中,我们将声明 props 类型,如下所示:

props: {
    user: String
}

在 <template> 部分,我们将 $route.params.user 替换为 user:

<template>
    <div class="about">
        <h1>About {{user}}</h1>
    </div>
</template>

输出仍然是相同的,如下面的屏幕截图所示:

image 2023 10 14 15 01 51 269
Figure 1. Figure 6.18: The About page renders the user passed through route params and mapped to props

除此之外,您还可以在路由配置的 props 属性中定义要传递的数据。现在可以将 props 声明为具有所需数据的对象,而不是布尔值,如下例所示:

{
    path: '/about',
    name: 'about',
    component: () => import(/* webpackChunkName: "about" */'../views/About.vue'),
    props: { age: 32 }
}

通过类似的步骤,我们将在 About.vue 中将 age 声明为 props 组件,并将其作为文本打印到屏幕上:

<template>
    <div class="about">
        <h1>About {{user}}</h1>
        <h2>Age: {{age}}</h2>
    </div>
</template>

<script>
export default {
    props: {
        user: String,
        age: Number
    }
}
</script>

现在,当单击 About 页面时,页面将渲染如下:

image 2023 10 14 15 04 31 854
Figure 2. Figure 6.19: About page rendered with the props preset in the router configuration

我们以前的用户数据不再可见!这是因为,现在 props 在 About 路由的配置中使用静态数据声明,并且不能从外部覆盖。无论我们在目标 router-link 组件中的 to 属性参数中传递什么值,它的值在整个应用程序导航过程中都将保持不变。

我们现在将学习如何将所选消息的内容传递到新消息页面并打印它。

练习 6.03:将所选消息的内容传递到新消息页面并将其打印出来

我们将从 Exercise 6.02 “将导航链接添加到 MessageFeed 路由” 继续,其中我们使用消息的 URL 路径定义了 MessageFeed 路由。该视图将在视图组件选项的 data 属性中渲染预定义消息的列表。

在本练习中,我们将创建一个新的 message 页面,指定用于渲染用户选择的消息内容。 它应该是可重复使用的。

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

  1. 在 ./src/views/ 文件夹中,我们创建一个名为 Message.vue 的新单文件组件。 该组件接收 string 类型的 content prop 并将其渲染在 <p> 标签下:

    <template>
        <div>
            <p>{{content}}</p>
        </div>
    </template>
    
    <script>
    export default {
        props: {
            content: {
                default: '',
                type: String
            }
        }
    }
    </script>
  2. 让我们将创建的视图组件注册到 ./src/router/index.js 中的现有路由。我们将新路由定义为一条消息,其路径为 /message。它还将接受 props: true 以便将传递给路由的所有参数相应地映射到相关的 prop。要使用的路由的完整列表如下:

    export const routes = [
        {
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/about',
            name: 'about',
            component: () => import(/* webpackChunkName: "about" */'../views/About.vue')
        },
        {
            path: '/messages',
            name: 'messageFeed',
            component: () => import(/* webpackChunkName: "messages" */ '../views/MessageFeed.vue')
        },
        {
            path: '/message',
            name: 'message',
            component: () => import(/* webpackChunkName: "message" */ '../views/Message.vue'),
            props: true
        }
    ]
  3. 由于路由已注册并可供使用,我们需要对 ./src/views/MessageFeed.vue 的 <template> 部分进行更改,以确保每个消息行现在可单击,并且在点击时将用户重定向到新路由。让我们用 router-click 替换 <p> 标签。因为我们已将新路由命名为 message,所以我们将设置 to 绑定到 { name: 'message' }

    <template>
        <div>
            <h2> Message Feed </h2>
            <div v-for="(m, i) in messages" :key="i" >
                <router-link :to="{ name: 'message'}">
                    {{ m }}
                </router-link>
            </div>
        </div>
    </template>
  4. 在 template 下,我们将添加一个脚本(script)标记,其中包含消息(messages)的一些示例数据:

    <script>
    export default {
        data() {
            return {
                messages: [
                    'Hello, how are you?',
                    'The weather is nice',
                    'This is message feed',
                    'And I am the fourth message'
                ]
            }
        }
    }
    </script>
  5. 当您打开 ./messages 页面时,所有消息现在都可以单击,如以下屏幕截图所示:

    image 2023 10 14 20 50 37 033
    Figure 3. Figure 6.20: Message Feed page after changing messages to be clickable
  6. 现在,当用户单击消息时,它将打开一个新页面。但是,页面内容将为空,因为我们没有向 <route-click> 组件传递任何内容参数,如下图所示:

    image 2023 10 14 21 13 59 501
    Figure 4. Figure 6.21: Message page with no content generated
  7. 让我们回到 ./src/views/MessageFeed.vue 并添加 params: { content: m }:

    <template>
        <div>
            <h2> Message Feed </h2>
            <div v-for="(m, i) in messages" :key="i" >
                <router-link :to="{ name: 'message', params: { content: m
                }}">
                {{ m }}
                </router-link>
            </div>
        </div>
    </template>
  8. 现在,当您单击第一条消息 Hello, how are you? 时,输出将如下所示:

    image 2023 10 14 21 16 57 703
    Figure 5. Figure 6.22: Message page with the clicked message’s content rendered

很简单,不是吗? 我们通过 router-link 以及组件的 params 和 props 的组合,动态地完成了从消息提要到单个选定消息的详细页面的流程。然而,这种方法有一个显着的缺点。

当您仍在第一条消息的 ./message 路径上时,让我们刷新页面。输出将与步骤 5 中的相同 - 一个空的内容页面。刷新时,路由会在没有传递任何内容参数的情况下触发,这与用户单击特定链接时不同,并且之前传递的参数不会保存或缓存。因此没有内容。

在下面的部分中,我们将学习如何拦截导航流并使用 Router Hooks 解决这个问题。