3.2Vue Router路由导航
router-link
默认类样式详解
<router-link>
会根据当前路由($route
)与 to
属性的匹配情况,自动添加以下 CSS 类:
1. router-link-active
- 触发条件:当链接对应的路由 被包含在当前路由中 时添加。
- 用途:适用于 嵌套路由 的场景。
- 注意:即使当前路径是
/users/123
,/users
的链接也会被激活。
2. router-link-exact-active
- 触发条件:当链接对应的路由 与当前路由完全精确匹配 时添加。
- 用途:适用于需要 精确匹配 的场景,避免父级路由在子路由激活时也被高亮。
router-link-exact-active
是router-link-active
的子集。也就是说,一个被精确匹配的链接,同时拥有两个类。
3. 修改默认样式类名
- 全局配置 Vue Router 实例
import Vue from 'vue'; import Router from 'vue-router';Vue.use(Router);const router = new Router({mode: 'history',base: process.env.BASE_URL,routes: [// ... 路由配置],linkActiveClass: 'my-active-class', // 修改默认的 active classlinkExactActiveClass: 'my-exact-active-class' // 修改默认的 exact active class });export default router;
在单个
<router-link>
上指定自定义类名<router-link to="/about" active-class="my-active-class" exact-active-class="my-exact-active-class" >About Us </router-link>
路由导航传参:
声明式导航:<router-link>
<router-link>
是 Vue Router 提供的一个组件,用于在模板中创建可点击的链接,从而触发路由跳转。
基本用法
最简单的形式是直接指定一个 to
属性来定义目标路径:
<router-link to="/">Go to Home</router-link>
这会生成一个指向根路径 /
的链接,当用户点击时会导航到对应的视图。
主要属性
to
(必需): 指定目标路由的位置。可以是一个字符串或一个描述目标位置的对象。<!-- 字符串 --> <router-link to="home">Home</router-link><!-- 使用对象 --> <router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link> <!-- 使用字符串路径(原对象形式使用 name 和 params)--> <router-link to="/user/123">User</router-link><!-- 带查询参数 --> <router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link> <!-- 带查询参数的字符串形式(原对象形式使用 path 和 query)--> <router-link to="/register?plan=private">Register</router-link>
replace
: 如果设置为true
,则导航不会留下历史记录,也就是说点击后退按钮不会回到这个页面。<router-link :to="{ path: '/abc'}" replace>Go to ABC</router-link>
append
: 设置为true
时,导航时会在当前路径前追加路径,而不是替换整个路径。<router-link :to="{ path: 'relative/path'}" append>Relative Path</router-link>
tag
: 自定义渲染的标签名,默认为<a>
标签。<router-link to="/foo" tag="li">Foo</router-link> <!-- 渲染为 <li>Foo</li> -->
编程式导航详解
1. $router.push()
push()
方法用于导航到新的路由,会向浏览器历史记录栈添加一条新记录。
使用字符串路径
// 字符串路径
this.$router.push('/home')// 带查询参数,结果为 /register?plan=private
this.$router.push('/register?plan=private')
// 或者使用对象形式
this.$router.push({ path: '/register', query: { plan: 'private' }})
查询参数
(query
)是以键值对的形式附加在 URL 的末尾,前面有一个问号 ?
分隔符。如果有多个查询参数,则用 &
符号连接。
http://example.com/user?id=123&name=john
在这个例子中,id=123
和 name=john
就是两个查询参数。
params
通常与 RESTful 风格的路由设计紧密相关.
/users # 表示所有用户这个资源集合
/users/123 # 表示 ID 为 123 的单个用户资源
/users/123/posts # 表示 ID 为 123 的用户的博客文章集合
使用路径 path
// 使用 path
this.$router.push({ path: '/user' })// path + params 不起作用,params 会被忽略
// ❌ 错误:/user 不会包含 params
this.$router.push({ path: '/user', params: { userId: 123 }})// ✅ 正确:使用 query
this.$router.push({ path: '/user', query: { userId: 123 }})
// 结果:/user?userId=123
使用路由名称 name
// 使用 name 和 params
this.$router.push({ name: 'user', params: { userId: 123 }})
// 结果:/user/123 (假设路由配置为 /user/:userId)// 使用 name 和 query
this.$router.push({ name: 'user', query: { id: 123 }})
// 结果:/user?id=123
2. $router.replace()
replace()
方法与 push()
类似,但不会向 history 添加新记录,而是替换当前记录。
// 替换当前路由
this.$router.replace('/home')
this.$router.replace({ path: '/home' })
this.$router.replace({ name: 'user', params: { userId: 123 }})
3. $router.go()
在 history 记录中前进或后退指定步数。
// 后退一步
this.$router.go(-1)// 前进一步
this.$router.go(1)// 前进三步
this.$router.go(3)// 如果没有足够的记录,会失败且不报错
this.$router.go(-100)
this.$router.go(100)
路由传参详解
1. params 传参
路由配置
const routes = [{path: '/user/:userId',name: 'user',component: User},{path: '/user/:userId/post/:postId',name: 'user-post',component: UserPost}
]
传递 params
// 使用 name + params
this.$router.push({ name: 'user', params: { userId: 123 }
})// 传递多个参数
this.$router.push({ name: 'user-post', params: { userId: 123, postId: 456 }
})// 声明式导航
<router-link :to="{ name: 'user', params: { userId: 123 }}">用户</router-link>
接收 params
// 在目标组件中
export default {created() {console.log(this.$route.params.userId) // 123console.log(this.$route.params.postId) // 456}
}
2. query 传参
传递 query
// 使用 path + query
this.$router.push({ path: '/user', query: { userId: 123, name: 'john' }
})// 使用 name + query
this.$router.push({ name: 'user', query: { userId: 123, name: 'john' }
})// 声明式导航
<router-link :to="{ path: '/user', query: { userId: 123 }}">用户</router-link>
<router-link :to="'/user?userId=123'">用户</router-link>
接收 query
// 在目标组件中
export default {created() {console.log(this.$route.query.userId) // 123console.log(this.$route.query.name) // john}
}
完整案例
1. 路由配置
// router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/views/Home.vue'
import User from '@/views/User.vue'
import UserProfile from '@/views/UserProfile.vue'
import UserPosts from '@/views/UserPosts.vue'Vue.use(Router)export default new Router({mode: 'history',routes: [{path: '/',name: 'home',component: Home},{path: '/user',component: User,children: [{path: ':id',name: 'user-profile',component: UserProfile,props: true // 将路由参数作为组件属性传递},{path: ':id/posts',name: 'user-posts',component: UserPosts}]}]
})
2. 导航示例
// Home.vue
export default {methods: {// 使用 path 导航goToUserByPath() {this.$router.push('/user/123')},// 使用 path + querygoToUserWithQuery() {this.$router.push({path: '/user/123',query: { tab: 'profile', lang: 'zh' }})},// 使用 name + paramsgoToUserByName() {this.$router.push({name: 'user-profile',params: { id: 123 }})},// 使用 name + params + querygoToUserWithParamsAndQuery() {this.$router.push({name: 'user-posts',params: { id: 123 },query: { page: 1, sort: 'date' }})},// 替换导航replaceToUser() {this.$router.replace({name: 'user-profile',params: { id: 123 }})}}
}
3. 接收参数
// UserProfile.vue
export default {// 使用 props 接收参数props: ['id'],created() {// 通过 $route 接收 paramsconsole.log('User ID:', this.$route.params.id)// 通过 $route 接收 queryconsole.log('Tab:', this.$route.query.tab)console.log('Language:', this.$route.query.lang)// 使用 props 接收(推荐)console.log('Props ID:', this.id)},watch: {// 监听路由变化(适用于同一个组件内不同参数的切换)'$route'(to, from) {if (to.params.id !== from.params.id) {this.fetchUserData(to.params.id)}}},methods: {fetchUserData(id) {// 根据新的用户ID获取数据}}
}
重要注意事项
path 与 params 的限制:
- 当使用
path
时,params
会被忽略 - 需要使用
query
来传递参数
- 当使用
name 与 params 的优势:
- 更安全,不受路由路径变化影响
- 可以正确传递参数
响应路由参数变化:
- 组件被复用时,
created
钩子不会被调用 - 需要使用
watch
监听$route
变化
- 组件被复用时,
编程式导航的返回值:
push()
和replace()
返回一个 Promise- 可以处理导航成功或失败的情况
this.$router.push('/home').then(() => {// 导航成功
}).catch(err => {// 导航被阻止或出错if (err.name !== 'NavigationDuplicated') {console.log(err)}
})
通过掌握这些路由导航和传参的方法,你可以构建出功能丰富、用户体验良好的单页应用。
$route
$route
监听不需要设置 deep: true
$route 对象的特性:
$route
是响应式的,每当 URL 发生变化(例如通过点击链接或调用$router.push()
),Vue Router 都会更新$route
对象,并触发相关的侦听器。$route
包含了诸如path
,name
,params
,query
等属性,这些属性代表了当前路由的状态。
监听 $route 变化的目的:
- 通常监听
$route
的目的是为了根据新的路由信息(如参数、查询等)执行某些操作,比如加载新数据或改变页面内容。 - 因为 Vue Router 在路由发生变化时会直接替换整个
$route
对象,而不是修改其内部属性,所以你只需要监听$route
本身的变化即可,而无需深入检查$route
内部属性的变化。
- 通常监听
为什么不需要
deep: true
:- 当路由发生跳转时,Vue Router 实际上是在替换整个
$route
对象,而不是修改它的某个属性。这意味着,如果你监听了$route
,那么每次路由变化都会触发监听器,无论这个变化是发生在params
,query
还是其他属性上。 - 设置
deep: true
主要是为了监听对象内部深层次的属性变化。然而,在$route
的情况下,由于它是作为一个整体被替换的,所以不需要这样做。简单地监听$route
就足够捕捉到所有的路由变化了。
- 当路由发生跳转时,Vue Router 实际上是在替换整个