vue3通过el-cascader实现动态菜单切换页面

时间:2024-03-23 17:09:35

如果只有一级菜单只会显示一个按钮
在这里插入图片描述

 <div style="width: 100%; margin-top: 10px; display: flex; align-items: center; border-bottom: 1px solid #ccc;">
    <template v-for="(menu, index) in cascaderData" :key="index">
      <el-cascader
          v-if="menu.children && menu.children.length > 0"
          style="width: 120px;"
          v-model="selectedOptions[index]"
          :options="menu.children"
          @change="handleCascaderChange(index, $event)"
          :placeholder="menu.label"
      >
      </el-cascader>

      <el-button :style="{color: buttonColor}" plain @click="handleSelect(String(index))" v-else>
        {{ menu.label }}
      </el-button>
    </template>
  </div>

菜单结构说明:component对应的就是你要跳转的页面组件,也就是上面import进来的组件。然后通过emitComponentChange方法来跳转对应页面。

<script setup>
import {useRouter} from 'vue-router';
import signal from '@/views/drawing/station/index';
import permutation from '@/views/drawing/permutationtable/permutation';
import gdgtable from '@/views/drawing/permutationtable/gdgtable';
import request from "../../../utils/request";
import {watch} from "vue";

import {useStationsStore} from "@/views/drawing/store/index";

const stationsStore = useStationsStore();

const router = useRouter();

const buttonColor = ref('black')

const drawCodeList = ref([]);

const xhjMenu = ref([])

const cascaderData =ref( [
  {
    value: '0',
    label: '基础数据',
    children: [],
    component: signal
  },
  {
    value: '1',
    label: '封面及目录',
    children: [
      {value: '1-1', label: '封面'},
      {value: '1-2', label: '目录'},
    ]
  },
  {
    value: '2',
    label: '测试1',
    children: [
      {value: '2-1', label: '测试1-1'},
      {value: '2-2', label: '测试1-2'},
    ]
  },
  {
    value: '4',
    label: '测试3',
    children: [
      {value: '4-1', label: '测试3-1', component: lsbtable},
      {value: '4-2', label: '测试3-2', component: dclsbtable},
    ]
  },
  {
    value: '6',
    label: '测试4',
    children: [
      {value: '6-1', label: '测试4-1', children: xhjMenu.value},	//这里用到了动态请求后端获取的三级菜单
      {value: '6-2', label: '测试4-2', component: dctable},
      {value: '6-3', label: '测试4-3'},
      {
        value: '6-4', label: '测试4-4', children: [
          {value: '6-4-1', label: '测试4-4-1', component: qdcjtable},
          {value: '6-4-2', label: '测试4-4-2'},
        ]
      },
      {value: '6-5', label: '测试4-5'},
    ]
  },
]);

// 用于存储选择的菜单项
const selectedOptions = ref([]);

// 处理 el-cascader 改变事件
const handleCascaderChange = (index, value) => {
  recoverButton(index);
  let menu = String(value)
  if (value.length === 2) {			//如果是二级菜单,截取第二位数据
    menu = String(value[1])
  }
  handleSelect(menu)
}

//处理菜单跳转事件
const handleSelect = async (menu) => {
  buttonColor.value = '#a7aab1'
  let component = findComponentByValue(cascaderData.value, menu);
  if (menu === '0') {
    buttonColor.value = 'black';
    recoverButton(menu);
  }
  if (menu === '7-3') {
    const type = await changeStation();
    if (type === 4) {
      emitComponentChange(jkgksktable);
    } else {
      emitComponentChange(jkgTktable);
    }
  }
  if (menu.includes('xhjtable')){
    let tuzhiCode = findTuZhiCodeByValue(cascaderData.value, menu);
    stationsStore.setTuzhiCode(tuzhiCode);
    emitComponentChange(component);
  }
  if (component != null) {
    emitComponentChange(component);
  }
};

//这个方法是用来跳转对应页面的
const emitComponentChange = (component) => {
  // 触发自定义事件,传递组件或其他数据
  const event = new CustomEvent('componentChange', {detail: component});
  window.dispatchEvent(event);
};

//将其他按钮恢复原状
function recoverButton(index) {
  console.log(selectedOptions.value)
  for (const item of cascaderData.value) {
    selectedOptions.value[item.value] = []; //全部恢复原状
    // if (parseInt(item.value) !== index) {
    //   selectedOptions.value[item.value] = [];//将除了当前选中的菜单框都恢复原状
    // }
  }
  console.log(selectedOptions.value)
}

// 匹配菜单页面
function findComponentByValue(data, targetValue) {
  for (let i = 0; i < data.length; i++) {
    const item = data[i];
    if (item.value === targetValue) {
      return item.component;
    }
    if (item.children && item.children.length > 0) {
      const result = findComponentByValue(item.children, targetValue);
      if (result) {
        return result;
      }
    }
  }
  return null;
}

// 获取图纸code
function findTuZhiCodeByValue(data, targetValue) {
  for (let i = 0; i < data.length; i++) {
    const item = data[i];
    if (item.value === targetValue) {
      return item.tuzhiCode;
    }
    if (item.children && item.children.length > 0) {
      const result = findTuZhiCodeByValue(item.children, targetValue);
      if (result) {
        return result;
      }
    }
  }
  return null;
}

listDingXingTuList().then((data) => { 	//这里通过请求后端接口动态获取三级菜单并赋值
  drawCodeList.value = data.data;
  cascaderData.value[6].children[0].children = drawCodeList.value.map(item => ({
    value: 'xhjtable'+item.id,		
    label: item.tu*me,
    component: xhjtable,
    tuzhiCode: item.tuzhiCode		//格式和一二级菜单保持一致,可以增加字段
  }));
})

</script>

下面是切换页面后要显示的目标页面,这里接收上面emitComponentChange 方法传递过来的组件

<template>
  <el-row>
    <el-col :span="20">
    
      <!-- 顶部菜单 -->
      <div v-if="showTop">
        <topmenu />
      </div>
      
      <!-- 右侧下方区域动态切换的内容 -->
      <div style="flex: 1;">
        <component :is="currentComponent" />
      </div>
      
    </el-col>
  </el-row>
</template>

<script setup>
import {onMounted, shallowRef} from 'vue';
import Topmenu from "./station/topmenu";

const currentComponent = shallowRef(signal);

//主动监听事件
onMounted(() => {
  window.addEventListener('componentChange', (event) => {
    const component = event.detail;
    // 在这里处理接收到的组件或其他数据
    currentComponent.value = component;
  });
});

getStationList()
</script>

还有一种方式是通过el-menu实现的,效果同上,使用的js方法都是一样的

<el-menu
      :default-active="activeIndex"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#f8f8f9"
      style="margin-top: 20px;margin-left: 1px"
  >
    <template v-for="(item, index) in cascaderData">
      <template v-if="!item.children">
        <el-menu-item :key="item.index" :index="item.value">
          {{ item.label }}
        </el-menu-item>
      </template>
      <el-sub-menu v-else :key="item.value" :index="item.value">
        <template #title>{{ item.label }}</template>
        <template v-for="(child, childIndex) in item.children">
          <template v-if="!child.children">
            <el-menu-item :key="child.value" :index="child.value">
              {{ child.label }}
            </el-menu-item>
          </template>
          <el-sub-menu v-else :key="child.value + '-sub'" :index="child.value">
            <template #title>{{ child.label }}</template>
            <el-menu-item
                v-for="(subItem, subIndex) in child.children"
                :key="subItem.value"
                :index="subItem.value"
            >
              {{ subItem.label }}
            </el-menu-item>
          </el-sub-menu>
        </template>
      </el-sub-menu>
    </template>
  </el-menu>