动态路由允许在路由路径中使用参数,实现灵活的路由匹配。当不同路由映射到同一个组件时,动态路由特别有用。
使用冒号 : 标记动态片段:
const routes = [
{ path: '/user/:id', component: User }
]
在组件中通过 $route.params 获取:
export default {
created() {
console.log(this.$route.params.id)
}
}
将路由参数作为组件 props 传入:
const routes = [
{ path: '/user/:id', component: User, props: true }
]
export default {
props: {
id: {
type: [String, Number],
required: true
}
},
created() {
console.log(this.id)
}
}
const routes = [
{ path: '/user/:userId/post/:postId', component: Post }
]
export default {
created() {
const { userId, postId } = this.$route.params
console.log(`用户 ${userId} 的文章 ${postId}`)
}
}
const routes = [
{
path: '/user/:userId/post/:postId',
name: 'post',
component: Post
}
]
<router-link :to="{ name: 'post', params: { userId: 1, postId: 2 } }">
查看文章
</router-link>
{ path: '/user/:id', component: User }
/user/123 → id = "123"
/user/abc → id = "abc"
使用正则限制为数字:
{ path: '/user/:id(\\d+)', component: User }
/user/123 → 匹配
/user/abc → 不匹配
{ path: '/user/:id?', component: User }
/user → id = undefined
/user/123 → id = "123"
{ path: '/user/:id+', component: User }
/user/1 → id = "1"
/user/1/2/3 → id = ["1", "2", "3"]
{ path: '/user/:id*', component: User }
/user → id = []
/user/1 → id = ["1"]
/user/1/2/3 → id = ["1", "2", "3"]
const routes = [
{ path: '/user/:id(\\d+)', component: User },
{ path: '/user/:name([a-z]+)', component: UserByName }
]
const routes = [
{ path: '/file/:path(.*)', component: File },
{ path: '/lang/:lang(en|zh|ja)', component: Lang }
]
const routes = [
{ path: '/user/:id', component: User },
{ path: '*', component: NotFound }
]
const routes = [
{ path: '/:pathMatch(.*)*', component: NotFound }
]
当从 /user/1 导航到 /user/2 时,复用同一个组件,不会触发生命周期:
export default {
created() {
console.log('只执行一次')
}
}
export default {
watch: {
'$route'(to, from) {
if (to.params.id !== from.params.id) {
this.fetchUser()
}
}
},
methods: {
fetchUser() {
const id = this.$route.params.id
}
}
}
export default {
beforeRouteUpdate(to, from, next) {
if (to.params.id !== from.params.id) {
this.fetchUser()
}
next()
}
}
<router-view :key="$route.fullPath"></router-view>
const routes = [
{ path: '/search', component: Search }
]
<router-link :to="{ path: '/search', query: { q: 'vue', page: 1 } }">
搜索
</router-link>
this.$router.push({
path: '/search',
query: { q: 'vue', page: 1 }
})
export default {
created() {
console.log(this.$route.query.q)
console.log(this.$route.query.page)
}
}
/search?q=vue&page=1
export default {
created() {
console.log(this.$route.hash)
}
}
/user#section1
router.addRoutes([
{ path: '/admin', component: Admin }
])
router.addRoute({
path: '/admin',
component: Admin
})
router.addRoute('parent', {
path: 'child',
component: Child
})
const router = new VueRouter({
routes: [
{ path: '/login', component: Login },
{ path: '/403', component: Forbidden }
]
})
async function initRoutes() {
const permissions = await fetchPermissions()
const dynamicRoutes = permissions.map(perm => ({
path: perm.path,
component: () => import(`@/views/${perm.component}.vue`)
}))
router.addRoutes(dynamicRoutes)
}
路由按定义顺序匹配:
const routes = [
{ path: '/user/profile', component: UserProfile },
{ path: '/user/:id', component: User }
]
/user/profile → 匹配第一个
/user/123 → 匹配第二个
const route = router.resolve('/user/123')
console.log(route.route.params)
const routes = [
{
path: '/user/:id',
name: 'user',
component: User,
props: true,
children: [
{
path: 'posts',
name: 'user-posts',
component: UserPosts
},
{
path: 'settings',
name: 'user-settings',
component: UserSettings
}
]
}
]
export default {
props: {
id: [String, Number]
},
computed: {
user() {
return this.$store.state.users[this.id]
}
},
watch: {
id: {
immediate: true,
handler(newId) {
this.$store.dispatch('fetchUser', newId)
}
}
}
}
const routes = [
{
path: '/post/:year(\\d{4})/:month(\\d{2})/:slug',
name: 'post',
component: Post,
props: true
}
]
export default {
props: {
year: String,
month: String,
slug: String
},
computed: {
post() {
return this.$store.getters.getPostBySlug(
this.year,
this.month,
this.slug
)
}
}
}
动态路由要点:
:param 语法定义动态片段$route.params 或 props: true