1. 为什么需要区分useRoute和useRouter?
在Vue 3的组合式API中,useRoute和useRouter这两个hook经常让开发者感到困惑。作为Vue Router的核心API,它们虽然名称相似,但职责和使用场景却完全不同。我在多个项目中都见过开发者混用这两个API导致的bug,比如:
- 错误地使用useRouter来获取当前路由参数
- 试图通过useRoute进行编程式导航
- 在路由守卫中混淆两者的使用方式
理解它们的区别,能帮助我们写出更健壮的路由逻辑。让我们先看一个典型的使用场景:
javascript复制import { useRoute, useRouter } from 'vue-router'
export default {
setup() {
const route = useRoute() // 获取当前路由信息
const router = useRouter() // 获取路由实例
const goToAbout = () => {
router.push('/about') // 正确:使用router进行导航
}
return {
id: route.params.id, // 正确:使用route获取参数
goToAbout
}
}
}
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. useRoute深度解析:路由信息的读取专家
2.1 useRoute的核心功能
useRoute返回的是一个响应式的路由对象,它包含了当前激活路由的所有信息。这个对象是只读的,你不能通过它修改路由状态。它的主要属性包括:
javascript复制{
path: '/user/123', // 当前路径
params: { id: '123' }, // 动态路径参数
query: { search: 'vue' }, // URL查询参数
hash: '#profile', // URL的hash值
fullPath: '/user/123?search=vue#profile', // 完整URL
matched: [], // 匹配的路由记录数组
meta: {}, // 路由元信息
name: 'user' // 路由名称
}
2.2 实际应用场景
- 获取动态路由参数:
javascript复制// 路由配置:{ path: '/user/:id' }
const route = useRoute()
console.log(route.params.id) // 输出动态id
- 监听路由变化:
javascript复制import { watch } from 'vue'
const route = useRoute()
watch(
() => route.params.id,
(newId) => {
console.log('ID变化了:', newId)
}
)
- 获取查询参数:
javascript复制// 访问 /search?q=vue
const route = useRoute()
console.log(route.query.q) // 输出"vue"
重要提示:useRoute返回的对象是响应式的,但直接解构会失去响应性。如果需要解构,应该使用toRefs:
javascript复制import { toRefs } from 'vue'
const { params, query } = toRefs(useRoute())
3. useRouter全面剖析:路由控制的指挥官
3.1 useRouter的核心能力
useRouter返回的是路由器的实例,它提供了编程式的路由控制方法。与useRoute不同,它是用来操作路由的,而不是读取当前路由信息。主要方法包括:
javascript复制{
push(), // 导航到新路由
replace(), // 替换当前路由
go(), // 在历史记录中前进/后退
back(), // 后退一步
forward(), // 前进一步
resolve(), // 解析目标路由位置
addRoute(), // 动态添加路由
getRoutes(), // 获取所有路由记录
hasRoute(), // 检查路由是否存在
removeRoute() // 移除路由
}
3.2 典型使用案例
- 编程式导航:
javascript复制const router = useRouter()
// 字符串路径
router.push('/users')
// 带参数的对象形式
router.push({ path: '/users', query: { page: 2 } })
// 命名路由
router.push({ name: 'user', params: { id: 123 } })
- 路由替换(不留下历史记录):
javascript复制router.replace('/login')
- 动态路由管理:
javascript复制// 添加新路由
router.addRoute({
path: '/settings',
component: SettingsView
})
// 移除路由
router.removeRoute('settings')
- 导航守卫:
javascript复制router.beforeEach((to, from) => {
// 返回false取消导航
if (!isAuthenticated()) return '/login'
})
4. 对比表格与常见误区
4.1 核心区别对照表
| 特性 | useRoute | useRouter |
|---|---|---|
| 返回内容 | 当前路由信息对象 | 路由器实例 |
| 主要用途 | 读取路由信息 | 控制路由行为 |
| 是否可修改路由 | 否 | 是 |
| 响应式 | 是 | 否 |
| 典型使用场景 | 获取参数、监听变化 | 编程导航、动态路由 |
| 是否包含历史记录 | 否 | 是 |
4.2 开发者常犯的错误
- 错误地使用useRouter读取参数:
javascript复制// 错误示范
const router = useRouter()
console.log(router.params.id) // undefined!
// 正确做法
const route = useRoute()
console.log(route.params.id)
- 尝试用useRoute进行导航:
javascript复制// 错误示范
const route = useRoute()
route.push('/about') // TypeError!
// 正确做法
const router = useRouter()
router.push('/about')
- 忽略响应式特性:
javascript复制// 错误示范(失去响应性)
const { params } = useRoute()
watch(params.id, () => { /* 不会触发 */ })
// 正确做法
const route = useRoute()
watch(() => route.params.id, () => { /* 会触发 */ })
5. 高级技巧与性能优化
5.1 路由状态共享模式
在大型应用中,为了避免重复调用useRoute,可以考虑在顶层组件获取路由状态后通过provide/inject共享:
javascript复制// 父组件
import { provide } from 'vue'
import { useRoute } from 'vue-router'
export default {
setup() {
const route = useRoute()
provide('routeState', route)
}
}
// 子组件
import { inject } from 'vue'
export default {
setup() {
const route = inject('routeState')
return { route }
}
}
5.2 路由监听优化
直接监听整个route对象可能会导致不必要的重新渲染:
javascript复制// 不够高效
watch(route, () => { /* 处理逻辑 */ })
// 更高效的做法
watch(
() => [route.params.id, route.query.page],
([id, page]) => { /* 精确监听 */ }
)
5.3 导航结果处理
router.push返回一个Promise,可以处理导航结果:
javascript复制router.push('/profile')
.then(() => {
console.log('导航成功')
})
.catch((err) => {
if (err.name === 'NavigationDuplicated') {
console.warn('重复导航')
}
})
6. 实战中的经验总结
- 路由参数类型问题:
javascript复制// route.params.id 始终是字符串
const id = route.params.id
// 如果需要数字类型,需要显式转换
const numericId = Number(id)
- 命名路由的优势:
javascript复制// 比硬编码路径更健壮
router.push({ name: 'user', params: { id: 1 } })
// 即使修改了路径配置,代码仍然有效
// 路由配置: { path: '/user/:id', name: 'user' }
- 动态路由的清理:
javascript复制// 添加动态路由后,记得在适当时候移除
const removeRoute = router.addRoute({ /* 配置 */ })
// 组件卸载时
onUnmounted(() => {
removeRoute()
})
- 路由元信息的妙用:
javascript复制// 路由配置
{
path: '/admin',
meta: { requiresAuth: true }
}
// 导航守卫中
router.beforeEach((to) => {
if (to.meta.requiresAuth && !isLoggedIn()) {
return '/login'
}
})
在Vue 3的组合式API生态中,正确理解和使用useRoute与useRouter是构建健壮路由系统的基石。useRoute是你的信息获取工具,而useRouter是你的导航控制器,它们各司其职又相互配合。记住这个简单的原则:需要"读"路由信息时用useRoute,需要"写"或"控制"路由时用useRouter。
