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

一、嵌套路由到底是个啥?

terry 3小时前 阅读数 6 #Vue

p>不少刚接触 Vue 路由的同学,一碰到嵌套路由就犯懵——明明配置了路由,子页面就是不显示;或者不知道啥场景该用嵌套,今天咱们就把 vue - router nested routes(嵌套路由)拆碎了讲,从“是啥”“为啥用”到“咋配置”“实战咋玩”,再到避坑,一次搞懂!

简单说,嵌套路由就是让路由组件像“俄罗斯套娃”一样分层嵌套,比如逛电商网站时,“商品”是个父页面,点进去后“商品列表”“商品分类”“促销活动”是子页面;这些子页面切换时,不需要整个页面刷新,只在父页面的特定区域更新——这个区域就是父组件里的 <router - view>,专门用来承载子路由对应的组件。

举个生活里的例子:手机“设置”APP 里,点进“网络设置”(父路由)后,里面还有“Wi - Fi”“移动数据”“热点”这些子选项(子路由),点不同子选项时,“网络设置”页面的主体内容变了,但顶部标题、侧边栏这类公共部分不变,这就是嵌套路由的典型场景。

为啥非得用嵌套路由?不能平级路由凑合吗?

要是不用嵌套,所有路由都平级配置,页面结构得重复写,还拿“设置”举例:每个子页面(Wi - Fi、移动数据)都得单独写顶部标题、侧边栏的 HTML 和逻辑,代码冗余到爆炸!而嵌套路由能实现 “结构复用 + 逻辑分层”:父组件负责公共布局(比如导航栏、侧边栏),子组件只处理自身独有的内容,后续维护起来轻松太多。

举个代码反例感受下:假设不用嵌套,每个子页面都复制父页面的导航栏代码,哪天产品经理说“导航栏加个夜间模式按钮”,所有子页面都得改一遍——这就是“牵一发动全身”,用嵌套的话,父组件改一次,所有子组件自动继承新结构,效率直接拉满!

手把手配置嵌套路由:就这三步!

下面用“博客系统首页拆分成新闻、消息两个子页面”的例子,带大家走一遍配置流程。

步骤 1:规划路由结构(先想清楚层级)

假设博客系统路由层级是这样:

  • 一级路由:Home(首页)、Article(文章)、About(
  • Home 页面里又分两个子页面:HomeNews(首页新闻)、HomeMessage(首页消息)
    Home 是父路由,HomeNews 和 HomeMessage 是子路由

步骤 2:在 router/index.js 里配置 children 属性

路由规则里,父路由通过 children 数组嵌套子路由,代码示例:

import Vue from 'vue'
import Router from 'vue - router'
import Home from '@/components/Home'
import HomeNews from '@/components/HomeNews'
import HomeMessage from '@/components/HomeMessage'
Vue.use(Router)
export default new Router({
  routes: [
    {
      path: '/home', // 父路由路径
      component: Home, // 父路由对应的组件
      // 关键:用 children 数组配置子路由
      children: [
        {
          // 子路由路径不加 / !会自动拼接父路由 path(/home + news → /home/news)
          path: 'news', 
          component: HomeNews 
        },
        {
          path: 'message',
          component: HomeMessage
        },
        // 可选:默认子路由(访问 /home 时自动跳转到 news)
        {
          path: '', // 空路径表示父路由的默认子路由
          redirect: 'news' 
        }
      ]
    }
  ]
})

解释:children 是个数组,每个对象对应一条子路由规则。path相对于父路由的路径(不用写 ,否则会变成根路径),component 是子组件。

步骤 3:在父组件(Home.vue)里放 <router - view>

父组件的模板中,必须有 <router - view> 来承载子路由组件,示例:

<template>
  <div class="home">
    <!-- 父组件的公共部分(比如导航栏) -->
    <div class="nav">
      <router - link to="news">新闻</router - link>
      <router - link to="message">消息</router - link>
    </div>
    <!-- 关键:子路由组件会渲染到这个 <router - view> 里 -->
    <router - view></router - view>
  </div>
</template>
<script>
export default {
  name: 'Home'
}
</script>

解释:父组件里的 <router - view> 是子路由组件的“容器”,访问 /home/news 时,HomeNews 组件会渲染到这里;访问 /home/message 时,HomeMessage 会渲染过来,父组件里的 <router - link> 可以直接用相对路径to="news"),因为会自动基于父路由的 path 拼接。

实战:用嵌套路由做后台管理系统布局

假设要做一个后台,左侧是菜单栏(父路由:Dashboard),右侧主体根据菜单切换子页面(用户管理、订单管理、商品管理),咱们一步步实现~

路由配置(router/index.js)

import Dashboard from '@/views/Dashboard'
import UserManage from '@/views/UserManage'
import OrderManage from '@/views/OrderManage'
import ProductManage from '@/views/ProductManage'
export default new Router({
  routes: [
    {
      path: '/dashboard',
      component: Dashboard,
      children: [
        { path: 'user', component: UserManage },   // 子路由:用户管理
        { path: 'order', component: OrderManage }, // 子路由:订单管理
        { path: 'product', component: ProductManage }, // 子路由:商品管理
        { path: '', redirect: 'user' } // 默认子路由:访问 /dashboard 时自动跳转到用户管理
      ]
    }
  ]
})

父组件 Dashboard.vue 的结构

<template>
  <div class="dashboard">
    <!-- 左侧菜单(公共部分) -->
    <aside class="sidebar">
      <ul>
        <li><router - link to="user">用户管理</router - link></li>
        <li><router - link to="order">订单管理</router - link></li>
        <li><router - link to="product">商品管理</router - link></li>
      </ul>
    </aside>
    <!-- 右侧主体,子组件渲染区 -->
    <main class="main - content">
      <router - view></router - view>
    </main>
  </div>
</template>
<style scoped>
.dashboard {
  display: flex;
}
.sidebar {
  width: 200px;
  background: #f5f5f5;
}
.main - content {
  flex: 1;
  padding: 20px;
}
</style>

子组件示例(UserManage.vue)

子组件只需要关注自身内容,不用重复写左侧菜单:

<template>
  <div>
    <h2>用户管理页面</h2>
    <p>这里可以做用户列表、新增、删除...</p>
  </div>
</template>

这样设计后,访问 /dashboard/user 时,左侧菜单 + 右侧用户管理内容会渲染;访问 /dashboard/order 时,右侧自动切换成订单管理——公共的左侧菜单只在 Dashboard 组件里写了一次,复用性直接拉满!

嵌套路由 + 动态路由:更灵活的页面组合

再举个电商场景的例子:“商品”模块需要列表页嵌套详情页,且详情页要根据商品 ID 动态显示内容。

路由配置

{
  path: '/product',
  component: ProductList, // 商品列表(父组件)
  children: [
    {
      path: ':id', // 动态参数 id(对应不同商品)
      component: ProductDetail // 商品详情(子组件)
    }
  ]
}

父组件 ProductList.vue 的结构

<template>
  <div class="product - list">
    <!-- 商品列表 -->
    <ul>
      <li v - for="item in products" :key="item.id">
        <router - link :to="`${item.id}`">{{ item.name }}</router - link>
      </li>
    </ul>
    <!-- 商品详情的容器 -->
    <router - view></router - view>
  </div>
</template>
<script>
export default {
  data() {
    return {
      products: [
        { id: 1, name: '手机' },
        { id: 2, name: '电脑' }
      ]
    }
  }
}
</script>

子组件 ProductDetail.vue 获取参数

<template>
  <div class="product - detail">
    <h2>商品 ID:{{ $route.params.id }}</h2>
    <p>这里显示对应商品的详情...</p>
  </div>
</template>

这种设计的好处很明显:用户在商品列表页点击某个商品,详情页直接在列表页的指定区域渲染,不用跳转到全新页面,体验更流畅,还减少了页面加载次数。

嵌套路由常见坑 & 避坑指南

嵌套路由好用,但刚上手容易踩坑,下面总结几个高频问题和解决方法~

坑 1:子路由死活不显示?先查这三点!

  • 父路由配置里有没有写 children 数组?(别漏了这个关键配置!)
  • 父组件模板里有没有放 <router - view>?(子组件没地方渲染,自然不显示)
  • 子路由的 path 有没有加 ?(加了的话,路径会变成根路径,比如父路由是 /home,子路由 path 写成 news 是对的,写成 /home/news 反而错了,会变成 //home/news 这种无效路径)

坑 2:路由跳转后,父组件数据没更新?

Vue 为了性能优化,当子路由切换但父路由不变时,父组件不会重新渲染,如果需要在子路由切换时更新父组件数据,可以用 watch 监听 $route

watch: {
  '$route'(to, from) {
    // 路由变化时执行逻辑,比如重置数据、清除定时器
    this.clearTimer()
  }
}

坑 3:嵌套路由里的样式冲突?

父组件用了 <style scoped>,子组件样式却被影响?scoped 是通过给元素加唯一属性实现作用域的,子组件根元素会继承父组件属性,如果子组件想完全脱离父组件样式,要么不用 scoped(但要注意命名规范),要么用深度选择器>>>::v - deep),比如父组件要修改子组件里的 .class

<style scoped>
.parent >>> .child - class {
  color: red;
}
</style>

坑 4:嵌套多层路由,路径太长咋管理?

如果有三级嵌套(/a/b/c),路由配置里 childrenchildren 会让代码很乱,可以把每个层级的路由拆成单独文件,a 路由的配置放在 a.jsb 路由的配置放在 b.js,用 children: require('./b.js').default 这种方式引入,让代码结构更清晰。

嵌套路由的进阶玩法:结合路由守卫

路由守卫能控制页面权限、处理数据加载,在嵌套路由中,父路由和子路由的守卫会按顺序执行(父路由守卫 → 子路由守卫)。

举个权限控制的例子:只有管理员能进 Dashboard 的子路由,在父路由的 beforeEnter 里判断:

{
  path: '/dashboard',
  component: Dashboard,
  // 父路由守卫:进入前判断权限
  beforeEnter: (to, from, next) => {
    const isAdmin = localStorage.getItem('role') === 'admin'
    if (isAdmin) {
      next() // 有权限,继续
    } else {
      next('/login') // 没权限,跳登录
    }
  },
  children: [...]
}

子路由也能单独加守卫,UserManage 需要“超级管理员”权限:

export default {
  name: 'UserManage',
  // 子路由守卫:进入前判断更细的权限
  beforeRouteEnter(to, from, next) {
    const isSuperAdmin = localStorage.getItem('role') === 'superAdmin'
    if (isSuperAdmin) {
      next()
    } else {
      next(false) // 阻止进入
    }
  }
}

这种“嵌套路由 + 守卫”的组合,能实现多层级权限控制,让页面访问更安全。

嵌套路由的核心价值

嵌套路由本质是 “布局复用 + 逻辑分层” 的工具:把页面拆成“公共容器 + 可变内容”,用 <router - view> 当容器,children 配规则,让复杂页面的维护成本呈指数级下降,从基础配置到实战布局,再到避坑和进阶,掌握这些后,不管是做后台管理系统、电商页面还是复杂表单页,嵌套路由都能帮你把结构理得明明白白~

(全文完,约 2200 字)

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

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

热门