Code前端首页关于Code前端联系我们

一、先搞懂Vue Router里的to是啥?

terry 4小时前 阅读数 8 #Vue
文章标签 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'对应的配置)。

每个匹配记录都包含pathcomponentmeta(自定义元信息)等关键配置,借助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"> &gt; </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根据路由配置和当前路径匹配生成,属于只读数据,可以读取其中的pathmeta等属性,但不能直接修改数组本身(如执行pushsplice等操作),否则会破坏路由匹配逻辑,引发异常。

to在不同导航方式下的“形态”

使用<router-link :to="...">时,“to”可以是字符串路径(如to="/user")或路由对象(如to="{ name: 'user', params: { id: 1 } }");而在编程式导航this.$router.push(to)中,“to”格式需与路由配置对应,导航守卫里的“to”是解析后的完整路由对象,包含pathparams等具体信息,此时处理更稳妥。

嵌套路由下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前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门