Vue实现侧边导航栏于Tab页关联

该博客详细分析了一种在Vue项目中,由于Element的导航菜单功能无法满足特定需求,如控制折叠、高亮及菜单组参数,而采用Ant Design Vue(Antd)和Element UI混合使用的情况。博主通过示例代码展示了如何使用Antd的菜单组件来实现侧边栏的折叠和高亮,并结合Element的Tab组件创建动态可编辑的Tab页。整个实现过程旨在记录并解决跨框架组件使用的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

技术栈

  • 侧边栏用 Antd
  • tab使用element

效果

请添加图片描述

<template>
	  <div class="main-card">
          <el-row>
            <el-col :span="3">
              <div class="menu-all">
                <div class="menu-head">
                  <span class="menu-head-title">仓库管理</span>/<span class="menu-head-title" @click="goBack"
                    >大屏</span
                  >
                </div>
                <!-- <div class="menu-body">
                <div class="menu-item" @click="openTabs(item)" v-for="item in menuItems" :key="item">
                  <i class="el-icon-s-home" v-if="item.value === '01'"></i>{{ item.name }}
                </div>
              </div> -->
                <a-menu
                  mode="inline"
                  theme="dark"
                  :openKeys="openKeys"
                  v-model="SelectedKeys"
                  @openChange="onOpenChange"
                >
                  <a-sub-menu v-for="item in menuItems" :key="item.value">
                    <span slot="title"
                      ><a-icon type="appstore" /><span>{{ item.name }}</span></span
                    >
                    <a-menu-item
                      v-for="childrenItem in item.children"
                      :key="childrenItem.value"
                      @click="addTabs(childrenItem)"
                      >{{ childrenItem.name }}
                    </a-menu-item>
                  </a-sub-menu>
                </a-menu>
              </div>
            </el-col>
            <el-col :span="21">
              <el-row>
                <el-col :span="24">
                  <div>
                    <el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="removeTab">
                      <el-tab-pane v-for="item in editableTabs" :key="item.name" :label="item.title" :name="item.name">
                        <component :is="item.content"></component>
                      </el-tab-pane>
                    </el-tabs>
                  </div>
                </el-col>
              </el-row>
            </el-col>
          </el-row>
        </div>
</template>
<script>
	export default {
		data(){
			return{
				   openKeys: [],//控制一级菜单折叠展开的数组 存放一级菜单的value
      SelectedKeys: '',//控制二级菜单高亮 存放二级菜单value
      //侧边导航菜单数组
      menuItems: [
        {
          name: '应入应出报表',
          value: '0',
          children: [
            {
              name: '应入库单量报表',
              value: '01',
              content: () => import('@/views/main/index/qtyReportIndex.vue'),
            },
            {
              name: '应入库台数报表',
              value: '02',
              content: () => import('@/views/main/index/qtyReportIndexQty.vue'),
            },
            {
              name: '应出库单量报表',
              value: '03',
              content: () => import('@/views/main/index/handoverReportIndex.vue'),
            },
            {
              name: '应出库台数报表',
              value: '04',
              content: () => import('@/views/main/index/handoverReportIndexQty.vue'),
            },
          ],
        },
        {
          name: '预测',
          value: '1',
          children: [
            {
              name: '到货登记',
              value: '11',
              content: () => import('@/views/main/index/asnHdrDockIndex.vue'),
            },
            {
              name: '仓库利用率',
              value: '12',
              content: () => import('@/views/main/index/whUteIndex.vue'),
            },
            {
              name: '库内库存',
              value: '13',
              content: () => import('@/views/main/index/imOdsStorageIndex.vue'),
            },
          ],
        },
        {
          name: '指标',
          value: '2',
          children: [
            {
              name: '单仓提货率',
              value: '201',
              content: () => import('@/views/main/index/singleWhDeliveryScaleIndex.vue'),
            },
            {
              name: '中转在库时长',
              value: '202',
              content: () => import('@/views/main/index/transitDurationInWhIndex.vue'),
            },
            {
              name: '重复SN',
              value: '203',
              content: () => import('@/views/main/index/dwExceptionBarcodeIndex.vue'),
            },
            {
              name: '盘点日清单',
              value: '204',
              content: () => import('@/views/main/index/inventoryRqIndex.vue'),
            },
            {
              name: '移库指标监控',
              value: '205',
              content: () => import('@/views/main/index/transferIndexIndex.vue'),
            },
            {
              name: '拣货库位分析汇总报表',
              value: '206',
              content: () => import('@/views/main/index/pickingByLocSumIndex.vue'),
            },
            {
              name: '装车报表汇总',
              value: '207',
              content: () => import('@/views/main/index/loadingSummaryIndex.vue'),
            },
            {
              name: '出库SN报错率',
              value: '208',
              content: () => import('@/views/main/index/dwBarcodeErrorRptIndex.vue'),
            },
            {
              name: '拣货库位分析明细',
              value: '209',
              content: () => import('@/views/main/index/dwPickFxmxIndex.vue'),
            },
            {
              name: '不按批次拣货库区维度',
              value: '210',
              content: () => import('@/views/main/index/notPickingByBatchIndex.vue'),
            },
          ],
        },
      ],
      editableTabsValue: '',//tab页当前active的item
      editableTabs: [],//tab页数组
			}
		},
		methods:{
	// 用于其他页面跳转来到主页并打开tab页的方法
	//	 goTable(item) {
     // this.openKeys = [item.value.substring(0, 1)]
     // this.SelectedKeys = item.value
     // this.$store.commit('updateHomeOrIndexSwitch', false)
     // this.openTabs(item)
    //},
		addTab(item) {
      let onOff = false;
      this.editableTabs.forEach((x) => {
        if (x.name == item.name) {
           this.editableTabsValue = item.name
           onOff=true
           return;
        }
      })
      if(!onOff){
      this.editableTabs.push({
        title: item.name,
        name: item.name,
        content: item.content,
      })
      this.editableTabsValue = item.name
      }
    },
    //关闭tab页触发 targetName = item.name
    removeTab(targetName) {
      let tabs = this.editableTabs
      let activeName = this.editableTabsValue
      if (activeName === targetName) {
        tabs.forEach((tab, index) => {
          if (tab.name === targetName) {
            let nextTab = tabs[index + 1] || tabs[index - 1]
            if (nextTab) {
              activeName = nextTab.name
            } else {
              this.openKeys = []
              this.SelectedKeys = ''
            }
          }
        })
      }
      this.editableTabsValue = activeName
      this.editableTabs = tabs.filter((tab) => tab.name !== targetName)
    },
		},
		watch:{
			    editableTabsValue(val) {
      this.menuItems.forEach((menuItem) => {
        if (menuItem.children) {
          menuItem.children.forEach((childrenItem) => {
            if (childrenItem.name === val) {
              this.openKeys = [childrenItem.value.substring(0, 1)]
              this.SelectedKeys = childrenItem.value
              return
            }
          })
        }
      })
    },
		}
	}
</script>

分析

这一套组件不能单凭element一个单一框架实现,侧边导航栏我们需要控制折叠,控制高亮,以及菜单组三个参数,而element的导航菜单控制折叠展开菜单组的参数是一个函数@open控制,所以我们没有办法通过代码去控制某个菜单组的展开收起所以跨框架做了这么一个功能 记录一下

在这里插入图片描述

Vue 3Element Plus提供了一种简单的方法来实现侧边菜单栏与标签之间的联动。下面是一个基本示例,演示了如何实现这一功能: 1. 首先,确保你已经安装了Vue 3Element Plus,并在项目中引入它们。 2. 创建一个侧边菜单栏组件(SideMenu),用于展示菜单项。这个组件可以使用Element Plus的Menu组件来创建。 ```html <template> <el-menu :default-active="activeMenu" @select="handleMenuSelect"> <el-menu-item v-for="item in menuItems" :key="item.path" :index="item.path"> {{ item.name }} </el-menu-item> </el-menu> </template> <script> export default { data() { return { activeMenu: '', // 当前选中的菜单项 menuItems: [ { name: '菜单1', path: '/menu1' }, { name: '菜单2', path: '/menu2' }, // 其他菜单项... ] } }, methods: { handleMenuSelect(index) { this.activeMenu = index; // 更新选中的菜单项 this.$router.push(index); // 导航到对应的路由 } } } </script> ``` 3. 创建一个标签组件(Tabs),用于展示已打开的面。这个组件可以使用Element Plus的Tabs组件来创建。 ```html <template> <el-tabs v-model="activeTab" type="border-card" @tab-remove="handleTabRemove"> <el-tab-pane v-for="tab in openedTabs" :key="tab.path" :label="tab.name" :name="tab.path"> <!-- 面内容 --> </el-tab-pane> </el-tabs> </template> <script> export default { data() { return { activeTab: '', // 当前选中的标签 openedTabs: [] // 已打开的标签 } }, methods: { addTab(tab) { const index = this.openedTabs.findIndex(item => item.path === tab.path); if (index === -1) { this.openedTabs.push(tab); } this.activeTab = tab.path; // 选中新打开的标签 }, removeTab(targetName) { const index = this.openedTabs.findIndex(item => item.path === targetName); if (index !== -1) { this.openedTabs.splice(index, 1); } }, handleTabRemove(targetName) { this.removeTab(targetName); if (targetName === this.activeTab) { this.activeTab = this.openedTabs[this.openedTabs.length - 1].path; } } } } </script> ``` 4. 在你的主面中,使用以上两个组件来实现联动效果。 ```html <template> <div> <side-menu></side-menu> <tabs></tabs> </div> </template> <script> import SideMenu from './SideMenu.vue'; import Tabs from './Tabs.vue'; export default { components: { SideMenu, Tabs } } </script> ``` 在这个例子中,当你点击侧边菜单栏的菜单项时,会更新选中的菜单项,并导航到对应的路由。同时,会在标签中打开一个新的标签。如果你点击已打开的标签的关闭按钮,会关闭该标签并自动选中最后一个打开的标签。 这样就实现侧边菜单栏与标签的联动效果。你可以根据自己的需求进行定制扩展。希望对你有所帮助!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

商朝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值