Vue Router中useRouter和useRoute的区别与记忆技巧
useRouter用于控制路由跳转(push/replace/go等方法),相当于路由器工具;
useRoute用于获取当前路由信息(params/query/path等),相当于路由数据。
记忆口诀:"Router跳转,Route参数"。
核心区分:
- useRouter返回Router实例,用于导航操作
- useRoute返回Route对象,包含当前路由信息
- 类比:Router是导航系统(控制器),Route是路况信息(数据)
常见错误:
- 混淆变量名(router/route)
- 在setup外部使用
- 解构失去响应性
参数对比:
- params:路径参数(/user/123),必须定义在路由配置中
- query:查询参数(?id=123),无需预定义,支持多值
useRouter vs useRoute 记忆技巧
这是一个非常常见的混淆点!
|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| useRoute | useRouter |
|
|
|
1. 快速对比表
| 维度 | useRouter | useRoute |
|---|---|---|
| 含义 | 路由器实例 | 当前路由信息 |
| 返回对象 | Router 对象 | Route 对象 |
| 主要用途 | 路由跳转、导航 | 获取路由参数、查询参数 |
| 常用方法/属性 | push(), replace(), go(), back(), currentRoute |
params, query, path, name, meta, fullPath |
| 类比 | 导航系统(控制器) | 当前路况信息(数据) |
| 记忆口诀 | Router 是工具,Route 是数据 |
2. 核心记忆方法
方法一:词源记忆法
javascript
// Router = 路由器(工具)
// - 用于控制路由:跳转、前进、后退
// - 类比:物理路由器,控制网络数据流向
// Route = 路由(信息)
// - 用于获取信息:参数、查询字符串、路径
// - 类比:路线信息,告诉你当前在哪里
方法二:首字母记忆法
R -> Router -> 控制 (Control)
R -> Route -> 数据 (Data)
记住:Router 是动作,Route 是状态
方法三:英文含义记忆
javascript
// Router = 路由器(名词-设备)
// - 你在"路由器"上执行操作
useRouter().push() // 操作路由器
useRouter().back() // 操作路由器
// Route = 路线(名词-信息)
// - 你获取"路线"上的信息
useRoute().params // 获取路线参数
useRoute().query // 获取路线查询参数
3. 使用场景对比
html
<script setup>
import { useRouter, useRoute } from 'vue-router'
// ✅ 正确用法
const router = useRouter() // 用于跳转
const route = useRoute() // 用于获取参数
// 使用场景 1: 路由跳转
function goToDetail() {
// 使用 router(工具)
router.push('/detail')
router.push({ name: 'Detail', params: { id: 1 } })
router.replace('/home')
router.back()
router.go(-1)
}
// 使用场景 2: 获取参数
function getRouteInfo() {
// 使用 route(数据)
console.log(route.params.id) // 路由参数
console.log(route.query.keyword) // 查询参数
console.log(route.path) // 当前路径
console.log(route.name) // 路由名称
console.log(route.meta.title) // 元信息
}
// 使用场景 3: 组合使用
function handleNavigation() {
// 获取当前路由信息(route)
const currentId = route.params.id
// 使用路由器跳转(router)
router.push(`/detail/${currentId}/edit`)
}
</script>
4. 形象化记忆
把路由比作"公交车系统"
javascript
// useRouter = 公交车调度中心
// - 可以控制车辆:发车、返回、调度
const router = useRouter()
router.push('/home') // 发车去 home
router.back() // 车辆返回
router.replace('/login') // 更换目的地
// useRoute = 公交车上的信息牌
// - 告诉你当前位置、路线信息
const route = useRoute()
route.path // 当前在哪条路
route.params // 车上乘客信息
route.query // 路况信息
5. 示例:在 watch 中监听路由变化
javascript
import { useRoute } from 'vue-router'
import { watch } from 'vue'
// ✅ 正确:监听 route 的变化
const route = useRoute()
watch(() => route.params.id, (newId) => {
console.log('路由参数变化', newId)
})
6. 代码模板记忆法
html
<script setup>
// 固定模板:永远记住这个顺序
import { useRouter, useRoute } from 'vue-router'
// 1. Router = 做操作(动词)
const router = useRouter()
// 2. Route = 取数据(名词)
const route = useRoute()
// 3. 使用时的区分:
// 要"做"什么 → 用 router
// 要"读"什么 → 用 route
// 实际应用
function submit() {
// 读取当前路由信息(读)
const userId = route.params.id
// 执行跳转(做)
router.push(`/user/${userId}/profile`)
}
</script>
7. 记忆口诀
口诀一(中文)
text
Router 跳转,Route 参数
想要跳转找 Router
想要参数找 Route
口诀二(英文)
text
Router for action (push, go, back)
Route for information (params, query, path)
8. 属性/方法速查表
| 需求 | 使用对象 | 代码示例 |
|---|---|---|
| 页面跳转 | router |
router.push('/path') |
| 返回上一页 | router |
router.back() |
| 前进/后退 | router |
router.go(-1) |
| 替换路由 | router |
router.replace('/path') |
| 获取 URL 参数 | route |
route.params.id |
| 获取查询参数 | route |
route.query.page |
| 获取当前路径 | route |
route.path |
| 获取路由名称 | route |
route.name |
| 获取路由元信息 | route |
route.meta.title |
| 监听路由变化 | route |
watch(() => route.params) |
| 获取完整 URL | route |
route.fullPath |
| 获取路由哈希 | route |
route.hash |
9. 常见错误及纠正
javascript
// ❌ 错误 1: 混淆变量名
// ✅ 纠正:变量名和方法名保持一致
const router = useRouter() // router 对应 useRouter
const route = useRoute() // route 对应 useRoute
// ❌ 错误 2: 在组件外使用:在 setup 外部或普通函数中
// ✅ 纠正:只能在 setup 或组合式函数中调用
function useCustomHook() {
const route = useRoute() // 在组合式函数中可以
return { id: route.params.id }
}
// ❌ 错误 3: 解构失去响应性
// ✅ 纠正:保持响应性
const route = useRoute()
const id = computed(() => route.params.id)
useRoute 常用属性:params vs query 完整对比
Vue Router 中:route.params.id 和 route.query.id 的区别
URLSearchParams :处理 URL 查询参数的接口
params:参数;参数个数(param 的复数)
query:n. 疑问,询问问号; v. 质疑,对......表示疑问;询问,提问
| 对比维度 | params | query |
|---|---|---|
| 定义 | 路由参数(路径参数) | 查询参数(URL 参数) |
| 位置 | 在 URL 路径中 | 在 URL 问号 ? 后面 |
| URL 示例 | /user/123/profile |
/user/profile?id=123 |
| 定义方式 | 路由配置中定义 :param |
无需预定义,直接使用 |
| 路由配置 | path: '/user/:id/profile' |
path: '/user/profile' |
| 必须性 | 必须在路由规则中定义 | 可选,无需预定义 |
| 刷新页面 | ✅ 参数保留 | ✅ 参数保留 |
| 编程式导航 | router.push({ name: 'user', params: { id: 123 } }) |
router.push({ path: '/user', query: { id: 123 } }) |
| 使用 name 导航 | ✅ 必须配合 name 使用 |
✅ 可配合 path 或 name |
| 使用 path 导航 | ❌ 不能使用 params | ✅ 可以使用 query |
| URL 编码 | 自动编码 | 自动编码 |
| 嵌套路由 | 支持多层嵌套 | 不涉及嵌套关系 |
| SEO 友好度 | 较高(路径包含关键词) | 一般(参数在查询字符串) |
| 数据类型 | 字符串 | 字符串或数组(重复参数) |
| 典型用途 | 资源 ID、唯一标识符 | 筛选、分页、搜索关键词 |
详细说明与代码示例
1. 定义方式对比
javascript
// 路由配置
const routes = [
{
// params: 在路径中定义
path: '/user/:id/profile',
name: 'user-profile',
component: UserProfile
},
{
// query: 路径中不定义参数
path: '/user/profile',
name: 'user-profile-query',
component: UserProfile
}
]
2. URL 格式对比
javascript
// params 格式
URL: /user/123/profile
// params 对象: { id: "123" }
// query 格式
URL: /user/profile?id=123&page=1&sort=desc
// query 对象: { id: "123", page: "1", sort: "desc" }
3. 编程式导航对比
javascript
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
// ========== params 导航 ==========
// ✅ 正确:必须使用 name
router.push({
name: 'user-profile',
params: { id: 123 }
})
// 结果: /user/123/profile
// ❌ 错误:path + params 不生效
router.push({
path: '/user/profile',
params: { id: 123 } // 会被忽略
})
// 结果: /user/profile (参数丢失)
// ========== query 导航 ==========
// ✅ 方式1: 使用 path + query
router.push({
path: '/user/profile',
query: { id: 123, page: 1 }
})
// 结果: /user/profile?id=123&page=1
// ✅ 方式2: 使用 name + query
router.push({
name: 'user-profile-query',
query: { id: 123, page: 1 }
})
// 结果: /user/profile?id=123&page=1
</script>
4. 获取参数对比
html
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// ========== params 获取 ==========
// URL: /user/123/profile
console.log(route.params.id) // "123"
console.log(route.params) // { id: "123" }
// ========== query 获取 ==========
// URL: /user/profile?id=123&page=1&tags=vue&tags=router
console.log(route.query.id) // "123"
console.log(route.query.page) // "1"
console.log(route.query.tags) // ["vue", "router"] (重复参数转为数组)
console.log(route.query) // { id: "123", page: "1", tags: ["vue", "router"] }
</script>
5. 嵌套路由对比
javascript
// 路由配置
const routes = [
{
path: '/user/:userId',
component: UserLayout,
children: [
{
// params 支持嵌套
path: 'profile/:profileId',
name: 'user-profile',
component: UserProfile
},
{
// query 不受嵌套影响
path: 'settings',
name: 'user-settings',
component: UserSettings
}
]
}
]
// params 嵌套访问
// URL: /user/123/profile/456
// route.params: { userId: "123", profileId: "456" }
// query 在任何层级都可以
// URL: /user/123/settings?tab=account¬ify=true
// route.query: { tab: "account", notify: "true" }
6. 刷新页面行为对比
html
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// 页面刷新后
// URL: /user/123/profile
// ✅ params 仍然存在
console.log(route.params.id) // "123"
// URL: /user/profile?id=123
// ✅ query 仍然存在
console.log(route.query.id) // "123"
// 两者刷新后都不会丢失
</script>
7. 数据类型处理
html
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
// ========== params 始终是字符串 ==========
// URL: /user/123/profile
const userId = route.params.id // "123" (字符串)
const numericId = Number(route.params.id) // 需要手动转换
// ========== query 支持多值 ==========
// URL: /list?tags=vue&tags=react&tags=angular
const tags = route.query.tags // ["vue", "react", "angular"] (数组)
// 单个值的情况
// URL: /list?page=1
const page = route.query.page // "1" (字符串)
// 参数不存在时
const sort = route.query.sort // undefined
</script>
8. 实际应用场景
html
<template>
<div>
<!-- params 场景:用户详情页 -->
<div v-if="route.params.id">
<h1>用户详情</h1>
<p>用户ID: {{ route.params.id }}</p>
<button @click="fetchUser(route.params.id)">
加载用户
</button>
</div>
<!-- query 场景:商品列表页 -->
<div>
<h1>商品列表</h1>
<!-- 筛选条件 -->
<select v-model="filters.category">
<option value="electronics">电子产品</option>
<option value="clothing">服装</option>
</select>
<input v-model="filters.keyword" placeholder="搜索" />
<!-- 分页 -->
<div class="pagination">
<button @click="changePage(currentPage - 1)">上一页</button>
<span>第 {{ currentPage }} 页</span>
<button @click="changePage(currentPage + 1)">下一页</button>
</div>
<!-- 排序 -->
<button @click="changeSort('price')">按价格排序</button>
</div>
</div>
</template>
<script setup>
import { useRoute, useRouter } from 'vue-router'
import { reactive, watch } from 'vue'
const route = useRoute()
const router = useRouter()
// params 场景:获取用户ID
const userId = route.params.id // 资源标识符
// query 场景:获取筛选条件
const filters = reactive({
category: route.query.category || 'all',
keyword: route.query.keyword || '',
page: Number(route.query.page) || 1,
sort: route.query.sort || 'default'
})
// 监听筛选条件变化,更新 URL query
watch(filters, () => {
router.push({
path: '/products',
query: {
category: filters.category,
keyword: filters.keyword,
page: filters.page,
sort: filters.sort
}
})
}, { deep: true })
// 翻页函数
function changePage(page) {
if (page < 1) return
filters.page = page
router.push({
path: '/products',
query: { ...route.query, page }
})
}
// 排序函数
function changeSort(sortBy) {
filters.sort = sortBy
router.push({
path: '/products',
query: { ...route.query, sort: sortBy }
})
}
</script>
9. 使用场景选择指南
| 场景 | 推荐使用 | 原因 |
|---|---|---|
| 用户详情页 | params |
ID 是资源的唯一标识,在路径中更语义化 |
| 文章详情页 | params |
/article/123 比 /article?id=123 更美观 |
| 搜索关键词 | query |
可选参数,适合 /search?q=vue |
| 分页参数 | query |
/list?page=2 符合 RESTful 规范 |
| 筛选条件 | query |
多条件组合,可选且可分享链接 |
| 排序参数 | query |
可选参数,不影响路由结构 |
| 多选框值 | query |
支持数组,如 ?tags=vue&tags=react |
| Tab 切换 | query 或 params |
如果 Tab 是资源的一部分用 params,否则用 query |
10. 完整示例:电商列表页
html
<script setup>
import { useRoute, useRouter } from 'vue-router'
import { ref, watch } from 'vue'
const route = useRoute()
const router = useRouter()
// 获取参数
// URL: /products/category/electronics?page=2&sort=price&brand=apple&brand=samsung
// params: 类别标识
const category = route.params.category // "electronics"
// query: 筛选条件
const page = Number(route.query.page) || 1
const sort = route.query.sort || 'default'
const brands = route.query.brand || [] // ["apple", "samsung"]
// 构建筛选器
const filters = ref({
page,
sort,
brands: Array.isArray(brands) ? brands : [brands]
})
// 更新 URL
function updateFilters() {
router.push({
name: 'products-category',
params: { category: category },
query: {
page: filters.value.page,
sort: filters.value.sort,
brand: filters.value.brands
}
})
}
// 监听筛选变化
watch(filters, updateFilters, { deep: true })
</script>
<template>
<div>
<h1>分类:{{ category }}</h1>
<div class="filters">
<select v-model="filters.sort">
<option value="default">默认排序</option>
<option value="price">价格排序</option>
<option value="sales">销量排序</option>
</select>
<div class="brands">
<label>
<input type="checkbox" value="apple" v-model="filters.brands">
Apple
</label>
<label>
<input type="checkbox" value="samsung" v-model="filters.brands">
Samsung
</label>
</div>
<div class="pagination">
<button @click="filters.page--">上一页</button>
<span>第 {{ filters.page }} 页</span>
<button @click="filters.page++">下一页</button>
</div>
</div>
</div>
</template>