动态路由

动态路由匹配

如果需要把不同路径的路由全都映射到同一个组件,例如,有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染,则可以在 vue-router 的路由路径中使用 “动态路径参数” (Dynamic Segment)来达到这个效果,如示例代码7-3-1所示。

<p>
    <router-link to="/user/1">用户1</router-link>
    <router-link to="/user/2">用户2</router-link>
</p>
<router-view></router-view>
const User = {
    template: '<div>用户id:{{$route.params.id}}</div>'
}
// 配置路由信息
const router = VueRouter.createRouter({
    history: VueRouter.createWebHashHistory(),
    routes: [
        { path: '/user/:id', component: User }
    ]
})

通过 :id 的方式可以指定路由的路径参数,使用冒号来标识。这样 “/user/1”“/user/2” 都可以匹配到 User 这个组件。在 User 组件插值表达式中使用 $route.params.id 可以获取这个 id 参数。如果是在方法中使用,则可以使用 this.$route.params.id,注意是 $route 而不是 $router

另外,也可以在一个路由中设置多段路径参数,对应的值都会设置到 $route.params 中,如图7-2所示。

Table 1. 图7-2 设置多段路径参数

模式

匹配路径

$route.params

/user/:username

/user/evan

{username: 'evan'}

/user/:username/post/:post_id

/user/evan/post/123

{username: 'evan', post_id: '123'}

使用这种路径参数的方式是在页面切换时直接传递参数,可以让 URL 地址更加简洁,也更符合 RESTful 风格。

如果想实现更高级的正则路径匹配,vue-router 也是支持的,例如下面的代码:

const router = VueRouter.createRouter({
    history: VueRouter.createWebHashHistory(),
    routes: [
        // 正则匹配,id为数字的路径
        { path: '/user/:id(\\d+)', component: User },
    ]
})

注意,在 Vue Router 4 中,移除了对于 * 路径正则匹配所有路径的方式,如果想要实现通配符匹配所有路径,可以通过参数 * 的方式实现,代码如下:

const router = VueRouter.createRouter({
    history: VueRouter.createWebHashHistory(),
    routes: [
        // 不再支持
        { path: '*', component: User },
        // 匹配/、/one、/one/two、/one/two/three任意字符
        { path: '/:chapters*', component: User },
    ]
})

当使用参数 * 的方式来匹配时,/ 后面的所有字符都会被当作 chapters 参数,代码如下:

<router-link to="/userabc/efg/1">用户1</router-link>
{ path: '/:chapters*', component: User },
{{$route.params.chapters}}// [ "userabc", "efg", "1" ]

响应路由变化

当使用路由来实现页面切换时,有时需要能够监听到这些切换的事件,例如从 /page1 切换到 /page2 时,可以使用监听属性来获取这个事件,如示例代码7-3-2所示。

示例代码7-3-2 响应路由变化
watch:{
    // to表示切换之后的路由,from表示切换之前的路由
    '$route'(to,from){
        // 在这里处理响应
        console.log(to,from)
    }
}

可以使用 watch 监听属性来监听组件内部的 $route 属性,当路由发生变化时,便会触发这个属性对应的方法,有两种情况需要注意一下:

  • 当路由切换对应的是同一个子组件时,例如上面的 User 组件,只是参数 id 不同,那么监听方法可以写在子组件 User 中。

  • 当路由切换对应的是不同的组件时,例如上面的 PageOnePageTwo 组件,那么监听方法需要写在根组件中才可以接收到变化。

两种写法代码如下:

const User = {
    template: '<div>用户id:{{$route.params.id}}</div>',
    watch:{// 子组件watch方法
        '$route'(to,from){ ... }
    }
}
...
const app = Vue.createApp({
    watch:{ // 根组件watch方法
        '$route'(to,from){ console.log(to,from) }
    }
})

设置在根组件的 watch 方法在上面两种情况下都会触发,所以建议统一在根组件中设置 watch 监听路由的变化。除了使用 watch 方法来监听路由的变化外,在 Vue Router 2.2 版本之后,引入了新的方案,叫作导航守卫。