跳至内容

带参数的动态路由匹配

很多时候,我们需要将具有给定模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该为所有用户渲染,但使用不同的用户 ID。在 Vue Router 中,我们可以使用路径中的动态段来实现这一点,我们称之为 _参数_

js
import User from './User.vue'

// these are passed to `createRouter`
const routes = [
  // dynamic segments start with a colon
  { path: '/users/:id', component: User },
]

现在,像 /users/johnny/users/jolyne 这样的 URL 都将映射到同一个路由。

一个 _参数_ 由冒号 : 表示。当路由匹配时,其 _参数_ 的值将作为 route.params 公开给每个组件。因此,我们可以通过将 User 的模板更新为以下内容来渲染当前用户 ID

vue
<template>
  <div>
    <!-- The current route is accessible as $route in the template -->
    User {{ $route.params.id }}
  </div>
</template>

你可以在同一个路由中拥有多个 _参数_,它们将映射到 route.params 上的对应字段。示例

模式匹配的路径route.params
/users/:username/users/eduardo{ username: 'eduardo' }
/users/:username/posts/:postId/users/eduardo/posts/123{ username: 'eduardo', postId: '123' }

除了 route.params 之外,route 对象还公开了其他有用的信息,例如 route.query(如果 URL 中有查询),route.hash 等。你可以在 API 参考 中查看完整细节。

此示例的工作演示可以在 这里 找到。

对参数更改做出反应

使用带参数的路由时需要注意的一点是,当用户从 /users/johnny 导航到 /users/jolyne 时,**将重用同一个组件实例**。由于这两个路由都渲染同一个组件,因此这比销毁旧实例然后创建一个新实例更有效。**但是,这也意味着组件的生命周期钩子将不会被调用**。

要对同一个组件中的参数更改做出反应,你可以简单地观察 route 对象上的任何内容,在本例中是 route.params

vue
<script setup>
import { watch } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()

watch(
  () => route.params.id,
  (newId, oldId) => {
    // react to route changes...
  }
)
</script>
vue
<script>
export default {
  created() {
    this.$watch(
      () => this.$route.params.id,
      (newId, oldId) => {
        // react to route changes...
      }
    )
  },
}
</script>

或者,使用 beforeRouteUpdate 导航守卫,它也允许你取消导航

vue
<script setup>
import { onBeforeRouteUpdate } from 'vue-router'
// ...

onBeforeRouteUpdate(async (to, from) => {
  // react to route changes...
  userData.value = await fetchUser(to.params.id)
})
</script>
vue
<script>
export default {
  async beforeRouteUpdate(to, from) {
    // react to route changes...
    this.userData = await fetchUser(to.params.id)
  },
  // ...
}
</script>

捕获所有 / 404 未找到路由

常规参数只会匹配 URL 片段之间的字符,这些字符由 / 分隔。如果我们想匹配**任何内容**,我们可以使用自定义 _参数_ 正则表达式,方法是在 _参数_ 后面添加括号中的正则表达式

js
const routes = [
  // will match everything and put it under `route.params.pathMatch`
  { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
  // will match anything starting with `/user-` and put it under `route.params.afterUser`
  { path: '/user-:afterUser(.*)', component: UserGeneric },
]

在这种特定情况下,我们使用括号中的 自定义正则表达式 并将 pathMatch 参数标记为 可选可重复。这允许我们通过将 path 拆分为数组来直接导航到路由,如果需要的话

js
router.push({
  name: 'NotFound',
  // preserve current path and remove the first char to avoid the target URL starting with `//`
  params: { pathMatch: route.path.substring(1).split('/') },
  // preserve existing query and hash if any
  query: route.query,
  hash: route.hash,
})

可重复参数 部分中查看更多内容。

如果你使用的是 历史模式,请确保按照说明正确配置你的服务器。

高级匹配模式

Vue Router 使用自己的路径匹配语法,灵感来自 express 中使用的语法,因此它支持许多高级匹配模式,例如可选参数、零个或多个/一个或多个要求,甚至自定义正则表达式模式。请查看 高级匹配 文档以探索它们。