在使用 Vue Router 开发单页应用(SPA)时,$route 和 $router 是两个频繁出现在组件中的全局属性。尽管名称相似,但它们的职责截然不同:$route 代表当前路由的状态(即“在哪里”),而 $router 是路由实例本身,用于导航和操作(即“怎么去”)。混淆两者不仅会导致逻辑错误,还可能引发不必要的性能问题。理解其本质差异,是掌握 Vue Router 的关键一步。

$route:当前路由的只读快照
$route 是一个响应式的只读对象,它包含了当前激活路由的所有信息。每当 URL 发生变化(无论是通过点击链接、调用 API 还是浏览器前进/后退),Vue Router 都会生成一个新的 $route 对象,并触发依赖该对象的组件重新渲染。
其核心属性包括:
path:当前路径字符串,如/user/123;params:动态路由参数,如{ id: '123' }(对应/user/:id);query:URL 查询参数,如{ page: '2', sort: 'desc' }(对应?page=2&sort=desc);name:当前路由的名称(如果定义了name属性);matched:匹配的路由记录数组,包含嵌套路由的层级信息;fullPath:完整的解析路径,包含 query 和 hash。
例如,在组件中可通过 this.$route.params.id 获取动态 ID,或通过 this.$route.query.keyword 读取搜索关键词。由于 $route 是响应式的,将其用于模板或计算属性中,能自动响应路由变化。
需要注意的是:$route 是不可变的。每次导航都会创建一个全新的对象,因此不能直接修改其属性。若需根据路由参数发起请求,应在 watch 或 created 钩子中监听 $route 变化。
$router:路由实例的操作接口
与 $route 不同,$router 是 Vue Router 的实例对象,在整个应用生命周期中保持唯一。它提供了编程式导航、路由守卫注册、路由信息查询等方法,是开发者主动控制路由行为的入口。
常用方法包括:
push(location):导航到新路由,向 history 栈添加一条记录(等价于<router-link>点击);replace(location):替换当前路由,不保留历史记录;go(n):在 history 记录中前进或后退 n 步;back()/forward():分别等价于go(-1)和go(1);addRoute():动态添加路由(Vue Router 4+);getRoutes():获取所有已注册的路由记录。
例如,用户登录成功后跳转首页:
this.$router.push({ name: 'Home' });
或在表单提交后替换当前页面,防止用户点击返回按钮回到提交页:
this.$router.replace({ path: '/success' });
此外,$router 还暴露了原始的路由配置(如 options.routes)和模式(history.mode),可用于调试或高级定制。
常见误区与最佳实践
误区一:用 $router 读取当前参数
错误写法:
// ❌ 错误:$router 没有 params 属性
const id = this.$router.params.id;
正确做法:
// ✅ 正确:从 $route 读取
const id = this.$route.params.id;
误区二:在 watch 中监听 $router
由于 $router 是固定实例,监听它没有意义。应监听 $route:
// ✅ 正确
watch: {
'$route'(to, from) {
// 处理路由变化
}
}
或者在 Vue 3 Composition API 中:
import { watch } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
watch(() => route.params.id, (newId) => {
// ...
});
最佳实践:按需使用,避免滥用
- 在模板中展示路径或参数时,直接使用
$route; - 在方法中需要跳转、替换或操作历史栈时,调用
$router的方法; - 若组件仅需响应路由变化而不执行导航,优先使用
watch($route)而非在每次created中重复逻辑; - 在组合式 API 中,使用
useRoute()和useRouter()替代this.$route/this.$router,提升类型安全性和可测试性。
总结:一句话区分
$route是“当前地址的信息”,$router是“控制地址跳转的工具”。
前者用于读取,后者用于操作。明确这一分工,就能避免绝大多数与路由相关的逻辑错误。