16.左侧导航菜单制作

左侧导航菜单制作

1. 修改路由,方便查看页面

index.ts

vue 复制代码
import { RouteRecordRaw, createRouter, createWebHistory } from "vue-router";
import Layout from '@/layout/Index.vue'

const routes: Array<RouteRecordRaw> = [
    {
        path: '/',
        name: 'home',
        component: Layout
    }
]

const router = createRouter({
    history: createWebHistory(),
    routes
})

export default router

2. 官网

https://element-plus.org/zh-CN/component/menu.html

3. 在Layout中新建Menu.vue

3.1代码如下

vue 复制代码
<template>
  <el-radio-group v-model="isCollapse" style="margin-bottom: 20px">
    <el-radio-button :value="false">expand</el-radio-button>
    <el-radio-button :value="true">collapse</el-radio-button>
  </el-radio-group>
  <el-menu
    default-active="2"
    class="el-menu-vertical-demo"
    :collapse="isCollapse"
    @open="handleOpen"
    @close="handleClose"
  >
    <el-sub-menu index="1">
      <template #title>
        <el-icon><location /></el-icon>
        <span>Navigator One</span>
      </template>
      <el-menu-item-group>
        <template #title><span>Group One</span></template>
        <el-menu-item index="1-1">item one</el-menu-item>
        <el-menu-item index="1-2">item two</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group Two">
        <el-menu-item index="1-3">item three</el-menu-item>
      </el-menu-item-group>
      <el-sub-menu index="1-4">
        <template #title><span>item four</span></template>
        <el-menu-item index="1-4-1">item one</el-menu-item>
      </el-sub-menu>
    </el-sub-menu>
    <el-menu-item index="2">
      <el-icon><icon-menu /></el-icon>
      <template #title>Navigator Two</template>
    </el-menu-item>
    <el-menu-item index="3" disabled>
      <el-icon><document /></el-icon>
      <template #title>Navigator Three</template>
    </el-menu-item>
    <el-menu-item index="4">
      <el-icon><setting /></el-icon>
      <template #title>Navigator Four</template>
    </el-menu-item>
  </el-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import {
  Document,
  Menu as IconMenu,
  Location,
  Setting,
} from '@element-plus/icons-vue'

const isCollapse = ref(true)
const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
</script>

<style scoped lang="scss">
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 400px;
}
</style>

3.2 效果图

3.3 修改样式

vue 复制代码
<template>
  <el-menu
    default-active="2"
    class="el-menu-vertical-demo"
    :collapse="isCollapse"
    @open="handleOpen"
    @close="handleClose"
    background-color="#0a2542"
  >

    <!-- 隐藏展开按钮 -->
    <el-radio-group v-model="isCollapse" style="margin-bottom: 20px;margin-left: 9px;">
      <el-radio-button :value="false" v-show="isCollapse" >|||</el-radio-button>
      <el-radio-button :value="true" v-show="!isCollapse">|||</el-radio-button>
    </el-radio-group>
    <el-sub-menu index="1">
      <template #title>
        <el-icon><location /></el-icon>
        <span>Navigator One</span>
      </template>
      <el-menu-item-group>
        <template #title><span>Group One</span></template>
        <el-menu-item index="1-1">item one</el-menu-item>
        <el-menu-item index="1-2">item two</el-menu-item>
      </el-menu-item-group>
      <el-menu-item-group title="Group Two">
        <el-menu-item index="1-3">item three</el-menu-item>
      </el-menu-item-group>
      <el-sub-menu index="1-4">
        <template #title><span>item four</span></template>
        <el-menu-item index="1-4-1">item one</el-menu-item>
      </el-sub-menu>
    </el-sub-menu>
    <el-menu-item index="2">
      <el-icon><icon-menu /></el-icon>
      <template #title>Navigator Two</template>
    </el-menu-item>
    <el-menu-item index="3" disabled>
      <el-icon><document /></el-icon>
      <template #title>Navigator Three</template>
    </el-menu-item>
    <el-menu-item index="4">
      <el-icon><setting /></el-icon>
      <template #title>Navigator Four</template>
    </el-menu-item>
  </el-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import {
  Document,
  Menu as IconMenu,
  Location,
  Setting,
} from '@element-plus/icons-vue'

//只允许展开一个子菜单
// const uniqueOpened = ref(true)
const isCollapse = ref(true)
const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
</script>

<style scoped lang="scss">
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 400px;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 230px;
  min-height: 400px;
}
.el-menu {
  border-right: none;
}

//主菜单颜色
:deep(.el-sub-menu .el-sub-menu__title){
	 color: #f5f4f4 !important;
}

/*子菜单文字颜色*/
:deep(.el-menu .el-menu-item){
	color: #e1e5ea;
}
/* 菜单点中文字的颜色 */

:deep(.el-menu-item.is-active){
	color: #f07810 !important;
}
/* 当前打开菜单的所有子菜单颜色 */

:deep(.is-opened .el-menu-item){
	background-color: #082343 !important;
}
/* 鼠标移动菜单的颜色 */

:deep(.el-menu-item:hover){
	background-color: #001528 !important;
}


</style>

3.4 效果图

4. 在Layout中新建MenuItem.vue

4.1 代码如下

vue 复制代码
<template>
    <template v-for="menu in menuList" :key="menu.path">
        <!-- 判断是否有子菜单 -->
        <el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.path">
            <template #title>
                <el-icon>
                    <!-- 动态组件 图标传入 -->
                    <component :is="menu.meta.icon"></component>
                </el-icon>
                <span>{{ menu.meta.title }}</span>
            </template>
            <!-- 递归渲染子菜单 -->
            <menu-item :menuList="menu.children"></menu-item>
        </el-sub-menu>
        <el-menu-item v-else :index="menu.path">
            <el-icon>
                <component :is="menu.meta.icon"></component>
            </el-icon>
            <template #title>
                {{ menu.meta.title }}
            </template>
        </el-menu-item>
    </template>
</template>

<script setup lang="ts">
// 接收父组件传递的menuList数据
defineProps(['menuList'])
</script>

<style scoped lang="less">

</style>

知识点补充

component是vue内置组件,主要作用为动态渲染组件,基本用法如下:

官网:动态组件 & 异步组件 | Vue.js (vueframework.com)

vue 复制代码
<!-- 动态组件由 vm 实例的 `componentName` property 控制 -->
<component :is="componentName"></component>
vue 复制代码
<template>
  <!-- router是否启用 vue-router 模式。 
    启用该模式会在激活导航时以 index 作为 path 
    进行路由跳转 使用 default-active 来设置加载时的激活项。 -->
  <el-menu
    default-active="/dashboard"
    class="el-menu-vertical-demo"
    :collapse="isCollapse"
    router
    unique-opened
    @open="handleOpen"
    @close="handleClose"
    background-color="#0a2542"
  >

    <!-- 隐藏展开按钮 -->
    <el-radio-group v-model="isCollapse" style="margin-bottom: 20px;margin-left: 9px;">
      <el-radio-button :value="false" v-show="isCollapse" >|||</el-radio-button>
      <el-radio-button :value="true" v-show="!isCollapse">|||</el-radio-button>
    </el-radio-group>
    <!-- 父组件传递数据 -->
    <MenuItem :menuList="menuList"></MenuItem>
  </el-menu>
</template>

<script lang="ts" setup>
import { ref,reactive } from 'vue'
import MenuItem from './MenuItem.vue';


//菜单数据
let menuList = reactive([
  {
    path: "/dashboard",
    component: "Layout",
    name: "dashboard",
    meta: {
      title: "首页",
      icon: "HomeFilled",
      roles: ["sys:dashboard"],
    },
  },
  {
    path: "/system",
    component: "Layout",
    name: "system",
    meta: {
      title: "系统管理",
      icon: "Setting",
      roles: ["sys:manage"],
    },
    children: [
      {
        path: "/adminUser",
        component: "/system/AdminUser",
        name: "adminUser",
        meta: {
          title: "管理员管理",
          icon: "UserFilled",
          roles: ["sys:adminUser"],
        },
      },
      {
        path: "/userList",
        component: "/system/UserList",
        name: "userList",
        meta: {
          title: "用户管理",
          icon: "Wallet",
          roles: ["sys:userList"],
        },
      },
      {
        path: "/menuList",
        component: "/system/MenuList",
        name: "menuList",
        meta: {
          title: "菜单管理",
          icon: "Menu",
          roles: ["sys:menu"],
        },
      },
    ],
  },
  {
    path: "/goodsRoot",
    component: "Layout",
    name: "goodsRoot",
    meta: {
      title: "商品管理",
      icon: "Histogram",
      roles: ["sys:goodsRoot"],
    },
    children: [
      {
        path: "/goodsType",
        component: "/goods/GoodsType",
        name: "goodsType",
        meta: {
          title: "商品分类",
          icon: "UserFilled",
          roles: ["sys:goodsType"],
        },
      },
      {
        path: "/unusedList",
        component: "/goods/UnusedList",
        name: "unusedList",
        meta: {
          title: "闲置商品",
          icon: "Wallet",
          roles: ["sys:unusedList"],
        },
      },
      {
        path: "/buyList",
        component: "/goods/BuyList",
        name: "buyList",
        meta: {
          title: "求购商品",
          icon: "Wallet",
          roles: ["sys:buyList"],
        },
      },
    ],
  },
  {
    path: "/order",
    component: "Layout",
    name: "order",
    meta: {
      title: "订单管理",
      icon: "Tickets",
      roles: ["sys:order"],
    },
    children: [
      {
        path: "/unusedOrder",
        component: "/order/UnusedOrder",
        name: "unusedOrder",
        meta: {
          title: "闲置订单",
          icon: "UserFilled",
          roles: ["sys:unusedOrder"],
        },
      },
      {
        path: "/buyOrder",
        component: "/order/BuyOrder",
        name: "buyOrder",
        meta: {
          title: "求购订单",
          icon: "Wallet",
          roles: ["sys:buyOrder"],
        },
      },
    ],
  },
  {
    path: "/comment",
    component: "Layout",
    name: "comment",
    meta: {
      title: "评论管理",
      icon: "Briefcase",
      roles: ["sys:comment"],
    },
    children: [
      {
        path: "/commentList",
        component: "/comment/CommentList",
        name: "commentList",
        meta: {
          title: "评论列表",
          icon: "UserFilled",
          roles: ["sys:commentList"],
        },
      },
    ],
  },
]);

//只允许展开一个子菜单
// const uniqueOpened = ref(true)
const isCollapse = ref(true)
const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
</script>

<style scoped lang="scss">
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 400px;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 230px;
  min-height: 400px;
}
.el-menu {
  border-right: none;
}



//主菜单颜色
:deep(.el-sub-menu .el-sub-menu__title){
	 color: #f5f4f4 !important;
}

/*子菜单文字颜色*/
:deep(.el-menu .el-menu-item){
	color: #e1e5ea;
}
/* 菜单点中文字的颜色 */

:deep(.el-menu-item.is-active){
	color: #f07810 !important;
}
/* 当前打开菜单的所有子菜单颜色 */

:deep(.is-opened .el-menu-item){
	background-color: #082343 !important;
}
/* 鼠标移动菜单的颜色 */

:deep(.el-menu-item:hover){
	background-color: #001528 !important;
}


</style>

4.3 在index.vue中引入

vue 复制代码
<template>
    <el-container class="mycontainer">
        <el-aside width="230px" class="asside">
            <Menu></Menu>
        </el-aside>
        <el-container>
            <el-header class="header">Header</el-header>
            <el-main class="mymain">Main</el-main>
        </el-container>
    </el-container>
</template>

<script setup lang="ts">
import Menu from "./Menu.vue"
</script>

<style scoped lang="scss">
.mycontainer{
    height: 100%;
    .asside{
        background-color: #0a2542;
        // 使宽度自适应
        width: auto;
    }
    .header{
        background-color: rgb(164, 194, 255);
    }
    .mymain{
        background-color: rgb(242, 187, 136);
    }
}
</style>

5. 最终效果

相关推荐
swimxu21 分钟前
npm 淘宝镜像证书过期,错误信息 Could not retrieve https://npm.taobao.org/mirrors/node/latest
前端·npm·node.js
zDarkBlue21 分钟前
VSCode工程中task.json的作用
ide·vscode·json
qq_3323942024 分钟前
pnpm的坑
前端·vue·pnpm
雾岛听风来29 分钟前
前端开发 如何高效落地 Design Token
前端
不如吃茶去29 分钟前
一文搞懂React Hooks闭包问题
前端·javascript·react.js
冯宝宝^34 分钟前
图书管理系统
服务器·数据库·vue.js·spring boot·后端
alwn35 分钟前
新知识get,vue3是如何实现在style中使用响应式变量?
前端
仁希'36 分钟前
《Unity3D高级编程之进阶主程》第二章 架构(三) - 架构的误区,如何做前端架构,以及如何架构Unity3D项目
笔记·unity·架构
来之梦1 小时前
uniapp中 uni.previewImage用法
前端·javascript·uni-app
野猪佩奇0071 小时前
uni-app使用ucharts地图,自定义Tooltip鼠标悬浮显示内容并且根据@getIndex点击事件获取点击的地区下标和地区名
前端·javascript·vue.js·uni-app·echarts·ucharts