Автор: маленькая картошка biubiubiu
Блог Сад:www.cnblogs.com/HouJiao/
Самородки:Талант /user/243617…
Публичный аккаунт WeChat: программа «Неизвестное сокровище» Юань
Содержание статей автора получено из его собственной практики.Если вы считаете, что это полезно для вас, вы можете поставить лайк для поощрения или оставить ценные комментарии.
предисловие
В ежедневной разработке реализована панель меню в проекте. Если вам нужно добавить новое меню, просто路由配置
Добавьте маршрут к маршруту, чтобы реализовать добавление меню.
Я считаю, что все такие же, как я, и иногда вам захочется реализовать строку меню самостоятельно. Тогда сегодня я поделюсь с вами всей идеей и кодом строки меню, которую я реализовал.
В этой статье основное внимание уделяется обобщению и совместному использованию одной из строк меню.
递归实现方式
,代码的优化
,菜单权限
Если это выходит за рамки данной статьи, некоторые советы также будут даны в соответствующих частях статьи.Существуют отдельные способы написания, которые не рекомендуются, и я надеюсь, что вы не будете на них ссылаться.В то же время могут быть некоторые подробные функции, которые не были обработаны или упомянуты, забудьте знать.
Окончательный эффект
Реализация этой строки меню содержит一级菜单
,二级菜单
а также三级菜单
Эти три типа могут в основном охватывать различные требования к меню в проекте.
Это меню будет реализовано шаг за шагом от простого к сложному позже.
Простая реализация
мы все знаемelement
при условииNavMenu
Компонент меню навигации, поэтому делаем простую реализацию этой строки меню прямо по документации.
Схема базовой архитектуры компоновки выглядит следующим образом:
Главное меню - menuIndex
Первое, чего нужно добиться, это菜单首页
Этот компонент, судя по предыдущей схеме архитектуры компоновки и со ссылкой на официальную документацию, очень прост в реализации.
<!-- src/menu/menuIndex.vue -->
<template>
<div id="menu-index">
<el-container>
<el-header>
<TopMenu :logoPath="logoPath" :name="name"></TopMenu>
</el-header>
<el-container id="left-container">
<el-aside width="200px">
<LeftMenu></LeftMenu>
</el-aside>
<el-main>
<router-view/>
</el-main>
</el-container>
</el-container>
</div>
</template>
<script>
import LeftMenu from './leftMenu';
import TopMenu from './topMenu';
export default {
name: 'MenuIndex',
components: {LeftMenu, TopMenu},
data() {
return {
logoPath: require("../../assets/images/logo1.png"),
name: '员工管理系统'
}
}
}
</script>
<style lang="scss">
#menu-index{
.el-header{
padding: 0px;
}
}
</style>
Верхняя панель меню - topMenu
Верхняя строка меню в основномlogo
а также产品名称
.
Логический код также очень прост, я вставлю код напрямую.
<!-- src/menu/leftMenu.vue -->
<template>
<div id="top-menu">
<img class="logo" :src="logoPath" />
<p class="name">{{name}}</p>
</div>
</template>
<script>
export default {
name: 'topMenu',
props: ['logoPath', 'name']
}
</script>
<style lang="scss" scoped>
$topMenuWidth: 80px;
$logoWidth: 50px;
$bg-color: #409EFF;
$name-color: #fff;
$name-size: 18px;
#top-menu{
height: $topMenuWidth;
text-align: left;
background-color: $bg-color;
padding: 20px 20px 0px 20px;
.logo {
width: $logoWidth;
display: inline-block;
}
.name{
display: inline-block;
vertical-align: bottom;
color: $name-color;
font-size: $name-size;
}
}
</style>
Этот код содержит父组件
Перейти к子组件
из двух данных.
props: ['logoPath', 'name']
Это родительский компонентmenuIndex
Перейти к сумасшедшемуtopMenu
Два данных , являютсяlogo图标的路径
а также产品名称
.
Эффект интерфейса после завершения выглядит следующим образом.
Левая строка меню - leftMenu
Сначала реализуйте простую строку меню в соответствии с официальной документацией.
<!-- src/menu/leftMenu.vue -->
<template>
<div id="left-menu">
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
:collapse="false">
<el-menu-item index="1">
<i class="el-icon-s-home"></i>
<span slot="title">首页</span>
</el-menu-item>
<el-submenu index="2">
<template slot="title">
<i class="el-icon-user-solid"></i>
<span slot="title">员工管理</span>
</template>
<el-menu-item index="2-1">员工统计</el-menu-item>
<el-menu-item index="2-2">员工管理</el-menu-item>
</el-submenu>
<el-submenu index="3">
<template slot="title">
<i class="el-icon-s-claim"></i>
<span slot="title">考勤管理</span>
</template>
<el-menu-item index="3-1">考勤统计</el-menu-item>
<el-menu-item index="3-2">考勤列表</el-menu-item>
<el-menu-item index="3-2">异常管理</el-menu-item>
</el-submenu>
<el-submenu index="4">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">工时管理</span>
</template>
<el-menu-item index="4-1">工时统计</el-menu-item>
<el-submenu index="4-2">
<template slot="title">工时列表</template>
<el-menu-item index="4-2-1">选项一</el-menu-item>
<el-menu-item index="4-2-2">选项二</el-menu-item>
</el-submenu>
</el-submenu>
</el-menu>
</div>
</template>
<script>
export default {
name: 'LeftMenu'
}
</script>
<style lang="scss">
// 使左边的菜单外层的元素高度充满屏幕
#left-container{
position: absolute;
top: 100px;
bottom: 0px;
// 使菜单高度充满屏幕
#left-menu, .el-menu-vertical-demo{
height: 100%;
}
}
</style>
Обратите внимание на код стиля меню, установите
绝对定位
, и установитеtop
,bottom
Сделайте так, чтобы высота меню заполнила экран.
На этом этапе посмотрите на эффект интерфейса.
В основном реализована простая компоновка меню.
Однако при разработке реального проекта содержимое строки меню может исходить из данных, возвращаемых нам бэкэндом, в том числе菜单名称
,菜单图标
так же как菜单之间的层级关系
.
В общем, наше меню генерируется динамически, а не фиксированным способом написания, как раньше. Поэтому ниже я реализую динамически генерируемое меню, а данные меню берутся из нашего路由配置
.
В сочетании с конфигурацией маршрутизации для достижения динамического меню
конфигурация маршрутизации
Во-первых, я разместил код конфигурации маршрутизации проекта.
import Vue from 'vue';
import Router from "vue-router";
// 菜单
import MenuIndex from '@/components/menu/menuIndex.vue';
// 首页
import Index from '@/components/homePage/index.vue';
// 人员统计
import EmployeeStatistics from '@/components/employeeManage/employeeStatistics.vue';
import EmployeeManage from '@/components/employeeManage/employeeManage.vue'
// 考勤
// 考勤统计
import AttendStatistics from '@/components/attendManage/attendStatistics';
// 考勤列表
import AttendList from '@/components/attendManage/attendList.vue';
// 异常管理
import ExceptManage from '@/components/attendManage/exceptManage.vue';
// 工时
// 工时统计
import TimeStatistics from '@/components/timeManage/timeStatistics.vue';
// 工时列表
import TimeList from '@/components/timeManage/timeList.vue';
Vue.use(Router)
let routes = [
// 首页(仪表盘、快速入口)
{
path: '/index',
name: 'index',
component: MenuIndex,
redirect: '/index',
meta: {
title: '首页', // 菜单标题
icon: 'el-icon-s-home', // 图标
hasSubMenu: false, // 是否包含子菜单,false 没有子菜单;true 有子菜单
},
children:[
{
path: '/index',
component: Index
}
]
},
// 员工管理
{
path: '/employee',
name: 'employee',
component: MenuIndex,
redirect: '/employee/employeeStatistics',
meta: {
title: '员工管理', // 菜单标题
icon: 'el-icon-user-solid', // 图标
hasSubMenu: true, // 是否包含子菜单
},
children: [
// 员工统计
{
path: 'employeeStatistics',
name: 'employeeStatistics',
meta: {
title: '员工统计', // 菜单标题,
hasSubMenu: false // 是否包含子菜单
},
component: EmployeeStatistics,
},
// 员工管理(增删改查)
{
path: 'employeeManage',
name: 'employeeManage',
meta: {
title: '员工管理', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
component: EmployeeManage
}
]
},
// 考勤管理
{
path: '/attendManage',
name: 'attendManage',
component: MenuIndex,
redirect: '/attendManage/attendStatistics',
meta: {
title: '考勤管理', // 菜单标题
icon: 'el-icon-s-claim', // 图标
hasSubMenu: true, // 是否包含子节点,false 没有子菜单;true 有子菜单
},
children:[
// 考勤统计
{
path: 'attendStatistics',
name: 'attendStatistics',
meta: {
title: '考勤统计', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
component: AttendStatistics,
},
// 考勤列表
{
path: 'attendList',
name: 'attendList',
meta: {
title: '考勤列表', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
component: AttendList,
},
// 异常管理
{
path: 'exceptManage',
name: 'exceptManage',
meta: {
title: '异常管理', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
component: ExceptManage,
}
]
},
// 工时管理
{
path: '/timeManage',
name: 'timeManage',
component: MenuIndex,
redirect: '/timeManage/timeStatistics',
meta: {
title: '工时管理', // 菜单标题
icon: 'el-icon-message-solid', // 图标
hasSubMenu: true, // 是否包含子菜单,false 没有子菜单;true 有子菜单
},
children: [
// 工时统计
{
path: 'timeStatistics',
name: 'timeStatistics',
meta: {
title: '工时统计', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
component: TimeStatistics
},
// 工时列表
{
path: 'timeList',
name: 'timeList',
component: TimeList,
meta: {
title: '工时列表', // 菜单标题
hasSubMenu: true // 是否包含子菜单
},
children: [
{
path: 'options1',
meta: {
title: '选项一', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
},
{
path: 'options2',
meta: {
title: '选项二', // 菜单标题
hasSubMenu: false // 是否包含子菜单
},
},
]
}
]
},
];
export default new Router({
routes
})
В самом начале этого кода мы вводим компоненты, которые нам нужно использовать, а затем настраиваем маршрутизацию.
Здесь используется метод прямого внедрения компонентов, и проект развивается
不推荐
Этот способ написания вы должны использовать懒加载
Путь
Настройка маршрутизации в дополнение к самым основнымpath
,component
так же какchildren
Кроме того,meta
элемент данных.
meta: {
title: '工时管理', // 菜单标题
icon: 'el-icon-message-solid', // 图标
hasSubMenu: true, // 是否包含子节点,false 没有子菜单;true 有子菜单
}
meta
Конфигурация, включенная в данные,菜单标题
(title
),图标的类名
(icon
)а также是否包含子节点
(hasSubMenu
).
согласно сtitle
,icon
Эти две элементы конфигурации, вы можете отобразить текущее меню标题
а также图标
.
hasSubMenu
Указывает, имеет ли текущий пункт меню подменю, если текущее меню содержит подменю (hasSubMenu
дляtrue
), элемент метки, соответствующий текущему меню,el-submenu
; в противном случае элемент метки меню, соответствующий текущему меню,el-menu-item
.
Включать ли подменю — очень важная логика.
meta.hasSubMenu
в этом параметре.
Реализовать многоуровневые меню на основе маршрутизации
После завершения настройки маршрутизации нам нужно реализовать меню в соответствии с маршрутизацией.
Получить конфигурацию маршрутизации
Поскольку мы хотим реализовать многоуровневое меню в соответствии с конфигурацией маршрутизации, первым шагом будет получение наших данных маршрутизации. Здесь я использую простой и грубый способ получить данные конфигурации маршрутизации:this.$router.options.routes
.
Этот метод также не подходит для ежедневной разработки проекта, потому что маршрут не может быть обработан в дальнейшем, когда он получен, например,
权限控制
.
Давайте напечатаем эти данные, когда компонент загрузится.
// 代码位置:src/menu/leftMenu.vue
mounted(){
console.log(this.$router.options.routes);
}
Результат печати следующий.
Вы можете видеть, что эти данные - это то, что у нас есть вrouter.js
Данные маршрутизации, настроенные в .
Для простоты использования я определяю эти данные как вычисляемое свойство.
// 代码位置:src/menu/leftMenu.vue
computed: {
routesInfo: function(){
return this.$router.options.routes;
}
}
Меню
Сначала реализуем一级菜单
.
Основная логика заключается в круговой маршрутизации данныхroutesInfo
, оценивать текущий маршрут при зацикливанииroute
Включать ли подменю, если да, то текущее меню используетel-submenu
Реализовано, иначе текущее меню используетel-menu-item
выполнить.
<!-- src/menu/leftMenu.vue -->
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
:collapse="false">
<!-- 一级菜单 -->
<!-- 循环路由数据 -->
<!-- 判断当前路由route是否包含子菜单 -->
<el-submenu
v-for="route in routesInfo"
v-if="route.meta.hasSubMenu"
:index="route.path">
<template slot="title">
<i :class="route.meta.icon"></i>
<span slot="title">{{route.meta.title}}</span>
</template>
</el-submenu>
<el-menu-item :index="route.path" v-else>
<i :class="route.meta.icon"></i>
<span slot="title">{{route.meta.title}}</span>
</el-menu-item>
</el-menu>
результат:
Как видите, наше меню первого уровня сгенерировано,员工管理
,考勤管理
,工时管理
Эти три меню имеют подменю, поэтому будет кнопка раскрывающегося списка.
Однако в настоящее время нет содержимого, по которому можно было бы щелкнуть. Далее мы реализуем три меню.二级菜单
.
Дополнительное меню
二级菜单
реализация и一级菜单
Логика та же: циклическая подмаршрутизацияroute.children
, оценка подмаршрутов при зацикливанииchildRoute
Включать ли подменю, если да, то текущее меню используетel-submenu
Реализовано, иначе текущее меню используетel-menu-item
выполнить.
Без лишних слов, давайте перейдем непосредственно к коду.
<!-- src/menu/leftMenu.vue -->
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
:collapse="false">
<!-- 一级菜单 -->
<!-- 循环路由数据 -->
<!-- 判断当前路由route是否包含子菜单 -->
<el-submenu
v-for="route in routesInfo"
v-if="route.meta.hasSubMenu"
:index="route.path">
<template slot="title">
<i :class="route.meta.icon"></i>
<span slot="title">{{route.meta.title}}</span>
</template>
<!-- 二级菜单 -->
<!-- 循环子路由`route.children` -->
<!-- 循环的时候判断子路由`childRoute`是否包含子菜单 -->
<el-submenu
v-for="childRoute in route.children"
v-if="childRoute.meta.hasSubMenu"
:index="childRoute.path">
<template slot="title">
<i :class="childRoute.meta.icon"></i>
<span slot="title">{{childRoute.meta.title}}</span>
</template>
</el-submenu>
<el-menu-item :index="childRoute.path" v-else>
<i :class="childRoute.meta.icon"></i>
<span slot="title">{{childRoute.meta.title}}</span>
</el-menu-item>
</el-submenu>
<el-menu-item :index="route.path" v-else>
<i :class="route.meta.icon"></i>
<span slot="title">{{route.meta.title}}</span>
</el-menu-item>
</el-menu>
Результат выглядит следующим образом:
можно увидеть二级菜单
успешно реализован.
третичное меню
三级菜单
Излишне говорить, и一级
,二级
Логика та же, вот код напрямую.
<!-- src/menu/leftMenu.vue -->
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
:collapse="false">
<!-- 一级菜单 -->
<!-- 循环路由数据 -->
<!-- 判断当前路由route是否包含子菜单 -->
<el-submenu
v-for="route in routesInfo"
v-if="route.meta.hasSubMenu"
:index="route.path">
<template slot="title">
<i :class="route.meta.icon"></i>
<span slot="title">{{route.meta.title}}</span>
</template>
<!-- 二级菜单 -->
<!-- 循环子路由`route.children` -->
<!-- 循环的时候判断子路由`childRoute`是否包含子菜单 -->
<el-submenu
v-for="childRoute in route.children"
v-if="childRoute.meta.hasSubMenu"
:index="childRoute.path">
<template slot="title">
<i :class="childRoute.meta.icon"></i>
<span slot="title">{{childRoute.meta.title}}</span>
</template>
<!-- 三级菜单 -->
<!-- 循环子路由`childRoute.children` -->
<!-- 循环的时候判断子路由`child`是否包含子菜单 -->
<el-submenu
v-for="child in childRoute.children"
v-if="child.meta.hasSubMenu"
:index="child.path">
<template slot="title">
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}}</span>
</template>
</el-submenu>
<el-menu-item :index="child.path" v-else>
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}}</span>
</el-menu-item>
</el-submenu>
<el-menu-item :index="childRoute.path" v-else>
<i :class="childRoute.meta.icon"></i>
<span slot="title">{{childRoute.meta.title}}</span>
</el-menu-item>
</el-submenu>
<el-menu-item :index="route.path" v-else>
<i :class="route.meta.icon"></i>
<span slot="title">{{route.meta.title}}</span>
</el-menu-item>
</el-menu>
можно увидеть工时列表
вниз三级菜单
уже отображается.
Суммировать
На данный момент мы объединили路由配置
Реализовано это динамическое меню.
Но такой код логически связан с三层嵌套
изfor
Цикл соответствует меню, которое у нас есть три слоя.
если мы имеем四层
,五层
Еще больше слоев меню, тогда нам придется вкладывать больше слоевfor
цикл. Очевидно, таким образом обнажаются передние слои.for
Дефекты циклов, поэтому нам нужно улучшить этот способ записи.
Реализовать динамическое меню рекурсивно
Мы говорили раньше一级
,二级
,三级
Логика реализации меню такая же: циклические подмаршруты, при циклическом определении, содержит ли субмаршрут подменю, если есть, то текущее меню используетel-submenu
Реализовано, иначе текущее меню используетel-menu-item
выполнить. Тогда такая логика наиболее удобна для использования递归
достигать.
Поэтому нам нужно выделить эту часть общей логики как независимый компонент, а затем рекурсивно вызвать этот компонент.
логическое разделение
<!-- src/menu/menuItem.vue -->
<template>
<div>
<el-submenu
v-for="child in route"
v-if="child.meta.hasSubMenu"
:index="child.path">
<template slot="title">
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}}</span>
</template>
</el-submenu>
<el-menu-item :index="child.path" v-else>
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}}</span>
</el-menu-item>
</div>
</template>
<script>
export default {
name: 'MenuItem',
props: ['route']
}
</script>
Следует отметить, что когда извлеченные компоненты зацикливаются на этот раз, цикл напрямуюroute
данные, этоroute
Что такое данные.
Давайте сначала посмотрим на источники данных циклов в предыдущих трех циклах.
Чтобы видеть яснее, я удалил часть нерелевантного контента в предыдущем коде.
<!-- src/menu/leftMenu.vue -->
<!-- 一级菜单 -->
<el-submenu
v-for="route in routesInfo"
v-if="route.meta.hasSubMenu">
<!-- 二级菜单 -->
<el-submenu
v-for="childRoute in route.children"
v-if="childRoute.meta.hasSubMenu">
<!-- 三级菜单 -->
<el-submenu
v-for="child in childRoute.children"
v-if="child.meta.hasSubMenu">
</el-submenu>
</el-submenu>
</el-submenu>
Как видно из кода выше:
一级菜单循环的是`routeInfo`,即最初我们获取的路由数据`this.$router.options.routes`,循环出来的每一项定义为`route`
二级菜单循环的是`route.children`,循环出来的每一项定义为`childRoute`
三级菜单循环的是`childRoute.children`,循环出来的每一项定义为`child`
Следуя этой логике, можно найти, что二级菜单
,三级菜单
Источник данных цикла тот же, то есть результат предыдущего циклаchildren
, а данные меню первого уровня поступают изthis.$router.options.routes
.
Мы вырвались раньшеmenuItem
компоненты, петляroute
данные, то есть一层菜单
еще二层
,三层菜单
, являются одним и тем же источником данных, поэтому нам необходимо унифицировать источник данных. Это, конечно, очень легко реализовать.Когда мы вызываем компонент, мы можем передавать ему разные значения.
Код
Публичные компоненты на переднем плане были разделены, а код позади очень легко реализовать.
Сначала вытащилmeunItem
компонент, реализующий逻辑判断
так же как递归调用自身
.
<!-- src/menu/menuItem.vue -->
<template>
<div>
<el-submenu
v-for="child in route"
v-if="child.meta.hasSubMenu"
:index="child.path">
<template slot="title">
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}}</span>
</template>
<!--递归调用组件自身 -->
<MenuItem :route="child.children"></MenuItem>
</el-submenu>
<el-menu-item :index="child.path" v-else>
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}}</span>
</el-menu-item>
</div>
</template>
<script>
export default {
name: 'MenuItem',
props: ['route']
}
</script>
с последующимleftMenu
компонент, вызовmenuIndex
Компонент, передающий необработанные данные маршрутизацииroutesInfo
.
<!-- src/menu/leftMenu.vue -->
<template>
<div id="left-menu">
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
:collapse="false">
<MenuItem :route="routesInfo"></MenuItem>
</el-menu>
</div>
</template>
<script>
import MenuItem from './menuItem'
export default {
name: 'LeftMenu',
components: { MenuItem }
}
</script>
<style lang="scss">
// 使左边的菜单外层的元素高度充满屏幕
#left-container{
position: absolute;
top: 100px;
bottom: 0px;
// 使菜单高度充满屏幕
#left-menu, .el-menu-vertical-demo{
height: 100%;
}
}
</style>
Окончательный результат здесь не показан и согласуется с результатом, которого нам нужно достичь.
Идеальная функция
До сих пор мы结合路由配置实现了菜单栏
Эта функция в основном завершена, но это строка меню, которой не хватает души.Поскольку в меню нет перехода, мы не можем перейти к соответствующей строке меню, щелкнув строку меню.组件
, так что давайте реализуем эту функцию дальше.
Есть два способа реализовать переход по меню, первый —NavMenu
Метод перехода, предоставляемый компонентом.
Второй — добавить в менюrouter-link
Прыгать в.
Тогда на этот раз я выбрал первый способ реализации прыжка, эта реализация требует выполнения двух шагов, первый шаг — включитьel-menu
Вверхrouter
; Второй шаг — установить навигациюindex
Атрибуты.
Тогда давайте реализуем эти два шага.
включить роутер в эл-меню
<!-- src/menu/leftMenu.vue -->
<!-- 省略其余未修改代码-->
<el-menu
:default-active="$route.path"
class="el-menu-vertical-demo"
router
:collapse="false">
<MenuItem :route="routesInfo">
</MenuItem>
</el-menu>
Установите свойство индекса навигации
Во-первых, я устанавливаю заголовок каждого меню в соответствии с тем, который нужно установить.index
указаны значения свойств.
index
Значение соответствует тому, что каждое меню настроено в маршрутизации.path
стоимость
首页
员工管理
员工统计 index="/employee/employeeStatistics"
员工管理 index="/employee/employeeManage"
考勤管理
考勤统计 index="/attendManage/attendStatistics"
考勤列表 index="/attendManage/attendList"
异常管理 index="/attendManage/exceptManage"
员工统计
员工统计 index="/timeManage/timeStatistics"
员工统计 index="/timeManage/timeList"
选项一 index="/timeManage/timeList/options1"
选项二 index="/timeManage/timeList/options2"
Затем просмотрите компоненты, вызываемые ранее рекурсивно, меню навигацииindex
установленchild.path
, чтобы ясно видетьchild.path
значение, я добавляю его справа от заголовка меню, чтобы отобразить его в интерфейсе.
<!-- src/menu/menuItem.vue -->
<!-- 省略其余未修改代码-->
<el-submenu
v-for="child in route"
v-if="child.meta.hasSubMenu"
:index="child.path">
<template slot="title">
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}} | {{child.path}}</span>
</template>
<!--递归调用组件自身 -->
<MenuItem :route="child.children"></MenuItem>
</el-submenu>
<el-menu-item :index="child.path" v-else>
<i :class="child.meta.icon"></i>
<span slot="title">{{child.meta.title}} | {{child.path}}</span>
</el-menu-item>
Также измените ширину строки меню на200px
Установить как400px
.
<!-- src/menu/menuIndex.vue -->
<!-- 省略其余未修改代码-->
<el-aside width="400px">
<LeftMenu></LeftMenu>
</el-aside>
Потом смотрим на эффект.
Его можно найти,child.path
Значение в том, что текущее меню настраивается в маршрутизацииpath
стоимость(router.js
настроен вpath
стоимость).
Затем возникает проблема, мы разобрались с соответствующими настройками для каждого заголовка меню.index
Значение свойства на данный момент установленоindex
значение не приемлемо. Но внимательно посмотрите на текущие настройки менюindex
Значение немного близко к нормальному значению, но отсутствует предыдущее менюpath
значение, если上一级菜单
изpath
значение и текущее менюpath
Значение может быть объединено для получения правильногоindex
стоило того.
Способ реализовать эту идею по-прежнему заключается в рекурсивном преобразовании текущего менюpath
передается как параметр вmenuItem
компоненты.
<!-- src/menu/menuIndex.vue -->
<!--递归调用组件自身 -->
<MenuItem
:route="child.children"
:basepath="child.path">
</MenuItem>
текущее менюpath
передается как параметр вmenuItem
После компонента, когда реализуется следующее меню, вы можете получить информацию о предыдущем меню.path
стоимость. Тогда компонент будетbasepath
значение и текущее менюpath
Значение выполняет соединение, так как текущее менюindex
стоимость.
<!-- src/menu/menuIndex.vue -->
<el-menu-item :index="getPath(child.path)" v-else>
</el-menu-item>
<script>
import path from 'path'
export default {
name: 'MenuItem',
props: ['route','basepath'],
data(){
return {
}
},
methods :{
// routepath 为当前菜单的path值
// getpath: 拼接 当前菜单的上一级菜单的path 和 当前菜单的path
getPath: function(routePath){
return path.resolve(this.basepath, routePath);
}
}
}
</script>
Взгляните еще раз на интерфейс.
Мы видим вторичное менюindex
Значение больше не является проблемой, но если вы внимательно посмотрите, вы обнаружите, что工时管理
-工时列表
два третичных меню подindex
Есть еще проблема со значением, оно отсутствует工时管理
это меню первого уровняpath
.
Эта проблема заключается в том, что мы называем само компонент, передаетсяbasepath
Что-то не так.
<!--递归调用组件自身 -->
<MenuItem
:route="child.children"
:basepath="child.path">
</MenuItem>
basepath
Проходит только предыдущее менюpath
, в рекурсии二级菜单
час,index
Значение一级菜单的path值
+二级菜单的path值
; что когда мы рекурсивно三级菜单
час,index
Значение二级菜单的path值
+三级菜单的path值
, вот почему工时管理-工时列表
два третичных меню подindex
Есть проблема со значением.
Итак, вотbasepath
Значение при рекурсии должно быть累积
, а не только предыдущее менюpath
стоимость. Итак, с преимуществом рекурсивного алгоритма,basepath
Значение также должно пройтиgetPath
способ обработки.
<MenuItem
:route="child.children"
:basepath="getPath(child.path)">
</MenuItem>
Окончательный полный код выглядит следующим образом.
<!-- src/menu/menuIndex.vue -->
<template>
<div>
<el-submenu
v-for="child in route"
v-if="child.meta.hasSubMenu"
:key="child.path"
:index="getPath(child.path)">
<template slot="title">
<i :class="child.meta.icon"></i>
<span slot="title">
{{child.meta.title}}
</span>
</template>
<!--递归调用组件自身 -->
<MenuItem
:route="child.children"
:basepath="getPath(child.path)">
</MenuItem>
</el-submenu>
<el-menu-item :index="getPath(child.path)" v-else>
<i :class="child.meta.icon"></i>
<span slot="title">
{{child.meta.title}}
</span>
</el-menu-item>
</div>
</template>
<script>
import path from 'path'
export default {
name: 'MenuItem',
props: ['route','basepath'],
data(){
return {
}
},
methods :{
// routepath 为当前菜单的path值
// getpath: 拼接 当前菜单的上一级菜单的path 和 当前菜单的path
getPath: function(routePath){
return path.resolve(this.basepath, routePath);
}
}
}
</script>
Удалите остальной код для отладки
окончательный эффект
В конце статьи здесь показан окончательный эффект от этой реализации.
选项一
а также选项二
Эти два трехуровневых меню не задаются в конфигурации маршрутизацииcomponent
, эти два меню просто для реализации трехуровневого меню, в демонстрации конечного результата я удалил эти два трехуровневых меню, настроенных в маршрутизацииздесь, в
leftMenu
компонентel-menu
включенныйunique-opened
существует
menuIndex
компонента, измените ширину левой строки меню на200px
о
автор
маленький картофель биубиубиу
Новичок в области фронтенда, который усердно учится, знания безграничны. Я твердо верю, что пока ты не перестаешь учиться, ты всегда можешь достичь того, чего хочешь.
В то же время он также человек, который любит котят.В доме есть красивая невысокая кошка по имени Тудо.
Блог Парк
Наггетс
Публичный аккаунт WeChat
Неизвестная сокровищница Юань
Я хочу поделиться фронтенд-знаниями со всеми на максимально простом и понятном языке.
Решив серьезно заняться делом и быть стойким человеком, я надеюсь, что вы многого здесь добьетесь.
Примечание автора
Небольшое резюме, приветствую всеобщее руководство~