分享一个VUE Element-UI 的多级菜单动态渲染的组件

以下是组件代码:

<template>
  <div class="navMenu">

    <label v-for="navMenu in navMenus">
      <el-menu-item v-if="navMenu.childs==null&&navMenu.entity&&navMenu.entity.state==='ENABLE'"
                    :key="navMenu.entity.id" :data="navMenu" :index="navMenu.entity.name" :route="navMenu.entity.value"
                    disabled="">
        <i :class="navMenu.entity.icon"></i>
        <span slot="title">{
  
  {navMenu.entity.alias}}</span>
      </el-menu-item>

      <el-submenu v-if="navMenu.childs&&navMenu.entity&&navMenu.entity.state==='ENABLE'"
                  :key="navMenu.entity.id" :data="navMenu" :index="navMenu.entity.name">
        <template slot="title">
          <i :class="navMenu.entity.icon"></i>
          <span> {
  
  {navMenu.entity.alias}}</span>
        </template>
        <NavMenu :navMenus="navMenu.childs"></NavMenu>
      </el-submenu>
    </label>

  </div>
</template>

<script>
  export default {
    name: 'NavMenu',
    props: ['navMenus'],
    data() {
      return {}
    },
    methods: {}
  }
</script>

<style scoped>

</style>

外部调用也比较简单

 <!--左侧菜单组件-->
      <el-menu
        default-active="0"
        class="el-menu-vertical-demo"
        @select="menuSelected"
        background-color="#F0F6F6"
        text-color="#3C3F41"
        active-text-color="black">
        <NavMenu :navMenus="leftMenus"></NavMenu>
      </el-menu>

最后看下效果:



值得一提的是,完成此菜单需要后端的配合,笔者这里后端给出的数据为:

{
    "entity": null,
    "childs": [
        {
            "entity": {
                "id": 1,
                "parentMenuId": 0,
                "name": "systemManage",
    
Vue2 + Element-UI 中实现**动态多级表头表格的导出功能**,与 Vue3 类似,但由于使用的是 `Element-UI`(非 Element Plus)和 Vue2 的 Options API,代码结构略有不同。我们仍然结合 [SheetJS / xlsx](https://github.com/SheetJS/sheetjs) 实现前端 Excel 导出。 --- ### ✅ 功能目标: 1. 使用 `Element-UI` 的 `<el-table>` 支持任意层级的**动态多级表头** 2. 点击按钮将当前表格(含合并表头)导出为 `.xlsx` 文件 3. 表头支持跨列合并(如“个人信息”合并“年龄”“城市”两列) --- ### ✅ 所需依赖 ```bash npm install xlsx file-saver ``` > `file-saver` 用于触发文件下载(可选,`XLSX.writeFile` 已内置) --- ### ✅ 完整示例代码(Vue2 + Element-UI) ```vue <template> <div style="padding: 20px;"> <el-button type="primary" @click="exportToExcel">导出为 Excel</el-button> <el-table :data="tableData" border style="width: 100%; margin-top: 20px" ref="tableRef" > <!-- 动态渲染多级表头 --> <el-table-column v-for="col in tableColumns" :key="col.prop" :prop="col.prop" :label="col.label" :width="col.width" > <el-table-column v-for="child in col.children || []" :key="child.prop" :prop="child.prop" :label="child.label" :width="child.width" /> </el-table-column> </el-table> </div> </template> <script> import * as XLSX from 'xlsx' import { saveAs } from 'file-saver' export default { name: 'DynamicTableExport', data() { return { // 表格数据 tableData: [ { name: '张三', info_age: 25, info_city: '北京', score_chinese: 88, score_math: 92 }, { name: '李四', info_age: 27, info_city: '上海', score_chinese: 76, score_math: 98 }, { name: '王五', info_age: 24, info_city: '深圳', score_chinese: 90, score_math: 85 } ], // 多级表头定义(支持 children) tableColumns: [ { prop: 'name', label: '姓名', width: 100 }, { label: '个人信息', children: [ { prop: 'info_age', label: '年龄', width: 80 }, { prop: 'info_city', label: '城市', width: 100 } ] }, { label: '成绩信息', children: [ { prop: 'score_chinese', label: '语文', width: 80 }, { prop: 'score_math', label: '数学', width: 80 } ] } ] } }, methods: { // 展平列定义,提取每列路径和表头层级 flattenHeaders(columns) { const result = [] columns.forEach(col => { if (col.children && col.children.length > 0) { col.children.forEach(child => { result.push({ prop: child.prop, groupLabel: col.label, fieldLabel: child.label }) }) } else { result.push({ prop: col.prop, groupLabel: null, fieldLabel: col.label }) } }) return result }, // 导出为 Excel exportToExcel() { const flatCols = this.flattenHeaders(this.tableColumns) // 构建两行表头 const headerRow1 = [] // 分组行(如“个人信息”) const headerRow2 = [] // 字段行(如“年龄”、“语文”) flatCols.forEach(col => { if (col.groupLabel) { headerRow1.push(col.groupLabel) headerRow2.push(col.fieldLabel) } else { headerRow1.push(col.fieldLabel) headerRow2.push('') // 没有列的,第二行为空 } }) // 合并单元格设置:记录第一行中相同分组的连续列进行合并 const merges = [] let lastGroup = null let startCol = 0 headerRow1.forEach((group, idx) => { if (group !== lastGroup) { // 如果上一个组存在且跨度大于1,则添加合并 if (lastGroup !== null && idx - startCol > 1) { merges.push({ s: { r: 0, c: startCol }, // start row=0, col=startCol e: { r: 0, c: idx - 1 } // end row=0, col=idx-1 }) } lastGroup = group startCol = idx } }) // 处理最后一组 if (headerRow1.length - startCol > 1 && lastGroup) { merges.push({ s: { r: 0, c: startCol }, e: { r: 0, c: headerRow1.length - 1 } }) } // 填充数据行 const dataRows = this.tableData.map(row => { return flatCols.map(col => row[col.prop] || '') }) // 创建工作表(空表开始) const worksheet = XLSX.utils.aoa_to_sheet([]) // 写入第一行(分组) XLSX.utils.sheet_add_aoa(worksheet, [headerRow1], { origin: 'A1' }) // 写入第二行(字段) XLSX.utils.sheet_add_aoa(worksheet, [headerRow2], { origin: 'A2' }) // 写入数据(从第3行开始) XLSX.utils.sheet_add_aoa(worksheet, dataRows, { origin: 'A3' }) // 设置列宽 const colWidths = flatCols.map(() => ({ wch: 12 })) worksheet['!cols'] = colWidths // 设置合并单元格 worksheet['!merges'] = merges // 创建工作簿 const workbook = XLSX.utils.book_new() XLSX.utils.book_append_sheet(workbook, worksheet, '数据表') // 导出文件 XLSX.writeFile(workbook, 'Vue2_ElementUI_多级表头导出.xlsx') } } } </script> <style scoped> .el-table { margin-top: 20px; } </style> ``` --- ### 🔍 代码解释 | 部分 | 说明 | |------|------| | `tableColumns` | 使用 `children` 字段实现二级表头,Element-UI 原生支持嵌套 `el-table-column` | | `flattenHeaders()` | 将嵌套结构展平,便于生成 Excel 表头和读取数据 | | `headerRow1` 和 `headerRow2` | 分别表示第一层(分组)和第二层(具体字段)表头 | | `merges` | 记录需要在 Excel 中合并的单元格范围(仅对第一行) | | `XLSX.utils.sheet_add_aoa` | 按二维数组方式写入指定位置 | | `worksheet['!merges']` | 设置 Excel 合并规则 | --- ### ✅ 输出效果(Excel) | 个人信息 | 成绩信息 | |----------------|--------------| | 年龄 | 城市 | 语文 | 数学 | | 25 | 北京 | 88 | 92 | | 27 | 上海 | 76 | 98 | 其中,“个人信息”跨两列合并,“成绩信息”也跨两列。 --- ### ✅ 注意事项 - **Element-UI 不支持三级以上嵌套表头**,本方案适用于最多两级。 - 若需更高层级,建议改用自定义表头模板或后端导出。 - 数据量大时避免前端导出,应由后端处理。 - 可通过 `ref="tableRef"` 获取表格 DOM,但此处无需依赖它来获取数据——因为我们自己维护了 `tableData` 和 `tableColumns`。 --- ### ✅ 扩展建议 - 抽象成混入(mixin)或封装为全局组件 - 添加导出前的确认弹窗 - 支持选择导出哪些列 - 自动调整列宽根据内容长度 ---
评论 46
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值