一、先搞懂Vue Router里的to是啥?
在Vue项目里用路由的时候,经常会碰到“to”和“matched”这些概念,尤其是做权限控制、面包屑导航的时候,总感觉得把它们吃透才能顺利用起来,那Vue Router里的to和matched到底是什么?怎么在项目里发挥作用?今天咱们就唠明白这些事儿。
Vue Router处理导航时,“to”代表目标路由对象,不管是用<router-link>
做声明式导航,还是用this.$router.push()
做编程式导航,“to”都描述了用户要前往的路由的完整信息。
举个编程式导航的例子:
this.$router.push({ path: '/user/123', name: 'userDetail', params: { id: 123 } })
这里传入的对象就是“to”的雏形,等导航流程推进后,“to”会被填充为包含path
(最终路径)、name
(路由命名)、params
(动态参数)、query
(查询参数)等属性的完整路由对象。
再看导航守卫的场景,比如全局前置守卫beforeEach
:
router.beforeEach((to, from, next) => { // “to”是即将进入的目标路由对象 console.log(to.path); // 打印目标页面的路径 next(); })
这里的“to”让我们在导航完成前,就能拿到目标路由的所有信息,方便做权限拦截、页面跳转控制这类操作。
“matched”又是什么来头?
“matched”是路由匹配记录的数组,Vue Router在处理导航时,会根据当前路径匹配对应的路由规则(包括嵌套路由的父路由和子路由),这些匹配成功的路由规则会被整合到matched
数组里。
举个嵌套路由的例子,假设路由配置长这样:
const routes = [ { path: '/dashboard', component: DashboardLayout, children: [ { path: 'analysis', component: AnalysisPage }, { path: 'statistics', component: StatisticsPage } ] } ]
当用户访问/dashboard/analysis
时,$route.matched
数组里会有两个元素:
- 第一个元素是父路由(
path: '/dashboard'
对应的配置); - 第二个元素是子路由(
path: 'analysis'
对应的配置)。
每个匹配记录都包含path
、component
、meta
(自定义元信息)等关键配置,借助matched
,我们能获取当前路径下所有层级的路由配置,这对处理嵌套路由逻辑特别关键。
to和matched怎么搭档干活?
理解了“to”和“matched”的基础概念,接下来看看它们如何配合解决实际开发问题。
权限控制:用matched检查路由元信息
很多项目中,部分页面需要登录后才能访问,这时可以给路由配置meta
字段,结合导航守卫和matched
做权限判断。
比如给需要权限的路由添加meta.requiresAuth
:
const routes = [ { path: '/profile', component: Profile, meta: { requiresAuth: true } }, { path: '/admin', component: AdminLayout, meta: { requiresAdmin: true }, children: [ { path: 'settings', component: AdminSettings } ] } ]
然后在全局前置守卫中,遍历to.matched
(因为嵌套路由下,父、子路由都可能配置权限,需要检查所有层级):
router.beforeEach((to, from, next) => { // 检查是否有路由要求登录 const requiresAuth = to.matched.some(record => record.meta.requiresAuth); // 检查是否有路由要求管理员权限 const requiresAdmin = to.matched.some(record => record.meta.requiresAdmin); if (requiresAuth && !isLogin()) { next({ path: '/login' }); // 未登录则跳转到登录页 } else if (requiresAdmin && !isAdmin()) { next({ path: '/403' }); // 无权限则跳转到403页 } else { next(); // 正常放行 } })
这里用to.matched.some()
检查是否存在权限要求的路由配置,避免了嵌套路由下权限判断遗漏的问题。
面包屑导航:用matched生成层级路径
面包屑能让用户清晰感知页面层级,而matched
数组的结构恰好对应路由层级,比如用户访问/dashboard/analysis
,面包屑需显示“仪表盘 > 分析页”,就可以通过matched
实现。
先写一个面包屑组件Breadcrumb.vue
:
<template> <div class="breadcrumb"> <span v-for="(record, index) in matched" :key="index" > <router-link :to="record.path">{{ record.meta.title }}</router-link> <span v-if="index !== matched.length - 1"> > </span> </span> </div> </template> <script> export default { computed: { matched() { // 从当前路由的matched中获取数据(也可在导航守卫中传递to.matched) return this.$route.matched; } } } </script>
接着在路由配置中为每个路由添加meta.title
:
const routes = [ { path: '/dashboard', component: DashboardLayout, meta: { title: '仪表盘' }, children: [ { path: 'analysis', component: AnalysisPage, meta: { title: '分析页' } } ] } ]
当用户进入/dashboard/analysis
时,面包屑组件会遍历$route.matched
,将每个层级的meta.title
渲染为可点击链接,自动生成层级导航,非常便捷。
动态设置页面标题:用matched读meta信息 document.title
)也能通过matched
动态设置,可以在全局路由守卫中,依据to.matched
里的meta.title
router.beforeEach((to, from, next) => { // 取最后一个匹配记录的title(通常子路由标题更具体) const lastRecord = to.matched[to.matched.length - 1]; if (lastRecord.meta.title) { document.title = lastRecord.meta.title; } else { document.title = '默认标题'; } next(); })
这样无论一级路由还是嵌套子路由,都能根据路由配置的meta.title
自动设置页面标题,无需在每个组件中单独编写document.title
。
用的时候得注意啥?
“to”和“matched”虽好用,但有些细节需留意,否则容易踩坑:
matched是“只读”的,别瞎改
matched
数组由Vue Router根据路由配置和当前路径匹配生成,属于只读数据,可以读取其中的path
、meta
等属性,但不能直接修改数组本身(如执行push
、splice
等操作),否则会破坏路由匹配逻辑,引发异常。
to在不同导航方式下的“形态”
使用<router-link :to="...">
时,“to”可以是字符串路径(如to="/user"
)或路由对象(如to="{ name: 'user', params: { id: 1 } }"
);而在编程式导航this.$router.push(to)
中,“to”格式需与路由配置对应,导航守卫里的“to”是解析后的完整路由对象,包含path
、params
等具体信息,此时处理更稳妥。
嵌套路由下matched的长度变化
嵌套路由层级越多,matched
数组长度越长(如三级嵌套路由,matched
包含祖父、父、子路由三条记录),处理权限、面包屑等场景时,要考虑数组长度变化,避免写死索引(如不要直接用to.matched[0]
,而是用遍历或取最后一个元素的方式)。
和其他路由概念咋区分?
为更清晰理解“to”和“matched”,再和几个易混淆的概念对比:
to vs $route
$route
是当前激活的路由对象,代表用户当前所在页面的路由;而“to”是即将进入的目标路由对象(常见于导航守卫),比如beforeEach
中,from
是当前路由,to
是目标路由,导航完成后$route
会等于to
。
matched vs routes
routes
是创建路由器时传入的完整路由配置数组(如new VueRouter({ routes: [...] })
里的routes
),包含所有定义的路由规则;而matched
是当前路径匹配到的路由规则数组,仅包含与当前路径对应的部分(含嵌套的父、子路由),简单说,routes
是“全部菜单”,matched
是“当前激活的菜单路径”。
再举个完整的小案例巩固下
假设做一个后台管理系统,包含登录页、仪表盘(嵌套分析页、统计页)、个人中心,需实现权限控制+面包屑+页面标题。
路由配置(带meta)
const routes = [ { path: '/login', component: Login, meta: { title: '登录' } }, { path: '/', redirect: '/dashboard/analysis', meta: { requiresAuth: true } }, { path: '/dashboard', component: DashboardLayout, meta: { title: '仪表盘', requiresAuth: true }, children: [ { path: 'analysis', component: Analysis, meta: { title: '数据分析' } }, { path: 'statistics', component: Statistics, meta: { title: '数据统计' } } ] }, { path: '/profile', component: Profile, meta: { title: '个人中心', requiresAuth: true } } ]
全局守卫做权限+标题
router.beforeEach((to, from, next) => { // 权限判断:检查是否需要登录 const requiresAuth = to.matched.some(record => record.meta.requiresAuth); const isLogin = localStorage.getItem('token'); // 假设用token判断登录状态 if (requiresAuth && !isLogin) { next('/login'); // 未登录则跳转到登录页 } else { // 设置页面标题:取最后一个匹配记录的title const lastRecord = to.matched[to.matched.length - 1]; document.title = lastRecord.meta.title || '后台管理系统'; next(); } })
面包屑组件
<template> <div class="breadcrumb"> <span v-for="(item, index) in matched" :key="index" > <router-link :to="item.path">{{ item.meta.title }}</router-link> <span v-if="index < matched.length - 1"> / </span> </span> </div> </template> <script> export default { computed: { matched() { return this.$route.matched; } } } </script> <style scoped> .breadcrumb { padding: 10px; background: #f5f7fa; } .breadcrumb a { color: #42b983; text-decoration: none; } </style>
在DashboardLayout里用面包屑
<template> <div class="dashboard-layout"> <Breadcrumb /> <router-view /> </div> </template> <script> import Breadcrumb from '@/components/Breadcrumb.vue'; export default { components: { Breadcrumb } } </script>
这套流程跑通后,当用户登录进入/dashboard/analysis
时:
- 全局守卫检查权限(已登录则放行); 被设置为“数据分析”;
- 面包屑显示“仪表盘 / 数据分析”;
- 页面渲染
Analysis
组件。
整个过程中,“to”和“matched”配合紧密,高效解决了权限、导航、标题等需求。
“to”是Vue Router中导航的目标路由对象,承载目标路由的全部信息;“matched”是匹配到的路由记录数组,能获取当前路径下所有层级的路由配置,把它们结合起来,权限控制、面包屑、页面标题等需求都能高效实现,实际项目中,多尝试用导航守卫+matched做权限、用matched渲染面包屑,慢慢就能摸透它们的规律,要是刚开始觉得绕,不妨把路由配置和matched数组打印出来看结构,结合案例多调试,理解起来会快很多~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。