前中台项目

svg图标原理;面包屑组件代码;tabs代码

1.SVG图标完整流程(极简流程图)

ini 复制代码
你把 hamburger.svg 放到 src/assets/icons
        ↓
vite‑plugin‑svg‑icons(启动时扫描文件夹)
        ↓
读取svg内容 → 包装成 <symbol id="icon‑hamburger">
        ↓
自动注入隐藏svg到页面DOM(display:none,肉眼看不见)
        ↓
main.js import 'virtual:svg-icons-register' 【必须!触发插件生效】
        ↓
你的页面使用组件 <m-svg-icon name="hamburger"/>
        ↓
组件计算 symbolId → #icon‑hamburger
        ↓
<use :xlink:href="#icon‑hamburger"> 找到页面里的symbol
        ↓
渲染图形 → 出现汉堡三条杠 ✅

必记3个坑

  1. 忘了 import 'virtual:svg-icons-register'全部图标空白
  2. 修改svg文件,不重启vite → 不更新symbol,图标不变
  3. svg源码写死 fill="#000" → 组件传color改不了颜色

对应代码位置速查

  1. vite.config.js → createSvgIconsPlugin,配置iconDirs图标目录
  2. main.js → import 'virtual:svg-icons-register'
  3. src/libs/svg‑icon/index.vue → m‑svg‑icon 组件
  4. 使用:<m-svg-icon name="hamburger"/>

回忆之前: name="hamburger" 不要写 icon‑,组件内部自动拼接成 #icon‑hamburger

2.面包屑核心来源:$route.matched

$route.matched 是路由匹配数组,保存当前路由每一层级

举例路由配置

js 复制代码
const routes = [
  {
    path: '/',
    name: 'home',
    meta: { title: '首页' },
    children: [
      {
        path: '/system',
        meta: { title: '系统管理' },
        children: [
          {
            path: '/system/user',
            meta: { title: '用户管理' }
          }
        ]
      }
    ]
  }
]

访问 /system/user$route.matched 得到数组:

js 复制代码
[
  { path:'/', meta:{title:'首页'} },
  { path:'/system', meta:{title:'系统管理'} },
  { path:'/system/user', meta:{title:'用户管理'} }
]

面包屑就遍历这个数组,取出每个的 meta.title,拼接:首页 / 系统管理 / 用户管理

Vue3 script‑setup 简易伪代码

vue 复制代码
<template>
  <div class="breadcrumb">
    <span v-for="item in breadList" :key="item.path">
      {{ item.meta.title }}
      <span v-if="!isLast(item)"> / </span>
    </span>
  </div>
</template>

<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()

// 直接拿到层级数组
const breadList = route.matched
</script>

关键点:

  1. 面包屑不会生成不在路由层级里的页面 ,完全靠路由配置的 meta.title
  2. 最后一项(当前页面)一般不给跳转链接,前面层级加 to 跳转
  3. 若依就是基于这套逻辑封装的 el‑breadcrumb

三者再快速复盘(面试脑图)

  1. 汉堡按钮:控制侧边栏展开/收起(按钮)
  2. 侧边导航栏:全部功能入口,跳转任意页面,读取路由全部菜单
  3. 面包屑route.matched,只看当前这条路径的层级,回退上层
  4. Tabs标签页:保存已经打开过的页面记录,可以来回切换、关闭

容易混淆点

  • 侧边导航:全部菜单(完整树)
  • 面包屑:当前路径的一条链(只一条)

面试简答:面包屑怎么实现? 答:通过 vue‑router 的 route.matched 获取路由匹配记录,遍历数组取出路由元信息 meta.title 渲染,除最后一项外绑定路由跳转,实现路径导航。

3.Tabs标签页(若依顶部可关闭页签)

效果:【首页】【用户管理】【角色管理】 ×

核心:自己维护一个数组,不是路由自带的route.matched 给面包屑用;Tabs是手动存你访问过的页面。

核心逻辑

  1. 访问路由的时候,把页面信息push进数组(不要重复添加)
  2. 循环数组渲染标签
  3. 点击标签:跳转到对应路由
  4. 点关闭×:把这条从数组删掉
  5. 不能关闭首页

伪代码 Vue3 setup

vue 复制代码
<template>
  <div class="tabs">
    <span
      v-for="tab in tabList"
      :key="tab.path"
      @click="$router.push(tab.path)"
    >
      {{ tab.title }}
      <!-- 首页不显示关闭按钮 -->
      <span v-if="tab.path !== '/' " @click="closeTab(tab)">×</span>
    </span>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()

// 存已经打开的页签,这个就是tabs数据源
const tabList = ref([
  { path: '/', title: '首页' } // 默认首页一定存在
])

// 监听路由变化,每次跳转路由触发
watch(
  () => route.path,
  () => {
    // 判断这个页签是否已经存在,不存在才push
    const has = tabList.value.some(item => item.path === route.path)
    if (!has) {
      tabList.value.push({
        path: route.path,
        title: route.meta.title
      })
    }
  },
  { immediate: true }
)

// 关闭标签
const closeTab = (tab) => {
  // 删除当前tab
  tabList.value = tabList.value.filter(item => item.path !== tab.path)
}
</script>

三个组件数据来源对比(重点,面试常考)

组件 数据来自哪里
侧边菜单导航 完整路由树 routes,过滤掉不需要显示的路由
面包屑 route.matched,当前路由向上的整条链路
Tabs标签页 自己维护数组,监听路由跳转手动收集访问记录

关键点:

  • 面包屑的数据路由自带;
  • Tabs路由没有给你存,需要自己写状态保存访问记录 ,刷新页面会全部消失(若依用sessionStorage持久化,刷新还在)

完整后台布局三件套总结

  1. 汉堡hamburger按钮 点击切换侧边栏展开/收起状态(存pinia)

  2. 侧边导航菜单 遍历完整路由配置树,渲染全部菜单,点击跳转页面

  3. 面包屑 breadcrumb route.matched,拿到当前路径链条,渲染路径导航

  4. Tabs多标签页 watch监听路由变化,手动维护数组,存放访问过的页面,支持切换关闭


面试简短口述版本

后台管理系统常见三个导航组件: 1.侧边菜单:遍历全部路由树生成,作为系统功能入口; 2.面包屑:使用route.matched获取当前路由匹配层级,取出meta标题渲染路径,实现上层跳转; 3.Tabs标签页:自己维护数组,监听路由变化收集访问过的页面,支持切换关闭,一般存sessionStorage做刷新持久化。

相关推荐
触底反弹1 小时前
🔐 前端鉴权不再难!手把手带你搞懂 JWT + Zustand + Axios 的完整登录方案
前端·axios
打呵欠的猫2 小时前
我用 AI 写了一个"需求翻译器",产品的 PRD 直接变成开发任务清单
前端·ai编程
fatcoder2 小时前
玩转Nginx 09 — 运维排障:三场"火灾"实战演练
前端·后端·nginx
前端玩坑坑2 小时前
View Transitions API 入门教程,优雅过度
前端
李高钢2 小时前
WPF MVVM Light(三):RelayCommand 命令与 Messenger 消息
前端·c#·wpf
lichenyang4532 小时前
Socket.IO 原理与技术选型
前端
qq21084629533 小时前
在python中什么是 self 和 cls?
开发语言·前端·python
我会冲击波3 小时前
vibe coding 一个多月,我把 Claude Code + Pi 做成了桌面 IDE,还给它移植了 VS Code 的编辑体验
前端·javascript·后端
kyson_3 小时前
前端性能优化全链路实践指南:从网络、缓存到渲染与监测
前端