vue 导出多级表头table 数据到excel

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue 导出多级表头table 数据到excel相关的知识,希望对你有一定的参考价值。

参考技术A 注意:在开始之前,先进行插件安装,参考: https://www.cnblogs.com/zhoulifeng/p/9974735.html

第二步:更改export2Excel.js里面的源码,本文示例为3级表头,可以根据需求,自行更改

//此处源码已被修改,autoWidt和bookType参数,先默认,(可以通过传参修改)

export function export_json_to_excel(excelData, autoWidth = true, bookType = 'xlsx') 

  /* original data */

  let multiHeader = excelData.multiHeader; // 第一级标题

  let multiHeader2 = excelData.multiHeader2; // 第二级标题

  let header = excelData.tHeader; // 第三级标题

  let data = excelData.transData; // table数据

  let defaultTitle = excelData.defaultTitle; // excel表的标题

  let merges = excelData.merges; // excel表合并单元格

  // console.log(multiHeader);

  // console.log(multiHeader2);

  // console.log(header);

  // console.log(data);

  // console.log(defaultTitle);

  // console.log(merges);

  data.unshift(header);

  //此处是第二行表头

  for (let i = multiHeader2.length - 1; i > -1; i--) 

    data.unshift(multiHeader2[i])

  

  //此处是第一行行表头

  for (let i = multiHeader.length - 1; i > -1; i--) 

    data.unshift(multiHeader[i])

  

  var ws_name = "SheetJS";

  var wb = new Workbook(),

    ws = sheet_from_array_of_arrays(data);

  //合并excel单元格和设置表格宽度

  if (merges.length > 0) 

    if (!ws['!merges']) ws['!merges'] = [];

    merges.forEach(item => 

      ws['!merges'].push(XLSX.utils.decode_range(item))

    )

  

  if (autoWidth) 

    /*设置worksheet每列的最大宽度*/

    const colWidth = data.map(row => row.map(val => 

      /*先判断是否为null/undefined*/

      if (val == null) 

        return 

          'wch': 10

        ;

      

      /*再判断是否为中文*/

      else if (val.toString().charCodeAt(0) > 255) 

        return 

          'wch': val.toString().length * 2

        ;

       else 

        return 

          'wch': val.toString().length

        ;

      

    ))

    /*以第一行为初始值*/

    let result = colWidth[0];

    for (let i = 1; i < colWidth.length; i++) 

      for (let j = 0; j < colWidth[i].length; j++) 

        if (result[j]['wch'] < colWidth[i][j]['wch']) 

          result[j]['wch'] = colWidth[i][j]['wch'];

        

      

    

    ws['!cols'] = result;

  

  //--------------------------------------------------------

  /* add worksheet to workbook */

  wb.SheetNames.push(ws_name);

  wb.Sheets[ws_name] = ws;

  var wbout = XLSX.write(wb, 

    bookType: 'xlsx',

    bookSST: false,

    type: 'binary'

  );

  var title = defaultTitle || '列表'

  saveAs(new Blob([s2ab(wbout)], 

    type: "application/octet-stream"

  ), title + ".xlsx")



第三步:元素,及页面method里添加的方法

<Button type="success" style="margin-right:5px;" @click="exportmulti">导出</Button>

exportmulti() 

      import("@/exportExcel/Export2Excel2").then(excel => 

        const multiHeader = [

          [

            "企业名称",

            "电子收费金额",

            "",

            "",

            "",

            "应退款金额",

            "",

            "",

            "",

            "",

            "",

            "",

            "",

            "",

            "电子收费资金明细分类",

            "",

            "",

            "",

            "",

            "",

            "",

            "",

            ""

          ]

        ];

        const multiHeader2 = [

          [

            "",

            "微信公众商户平台",

            "微信开放商户平台",

            "支付宝",

            "合计",

            "2016.9.1前",

            "",

            "2016.9.1-2017.12.31",

            "",

            "2018.1.1-2019.12.31",

            "",

            "2020.1.1后",

            "",

            "合计",

            "2016.9.1前",

            "",

            "2016.9.1-2017.12.31",

            "",

            "2018.1.1-2019.12.31",

            "",

            "实收",

            "",

            "合计"

          ]

        ];

        const tHeader = [

          "",

          "",

          "",

          "",

          "",

          "微信",

          "支付宝",

          "微信",

          "支付宝",

          "微信",

          "支付宝",

          "微信",

          "支付宝",

          "",

          "微信",

          "支付宝",

          "微信",

          "支付宝",

          "微信",

          "支付宝",

          "微信",

          "支付宝",

          ""

        ];

        // table对应导入字段

        const filterVal = [

          "companyName",

          "eWeChatMountApp",

          "eWeChatMountApp",

          "eAlipay",

          "eTotal",

          "reWeChatBefore",

          "reAlipayBefore",

          "reWeChatBe",

          "reAlipayBe",

          "reWeChatTe",

          "reAlipayTe",

          "reWeChatAf",

          "reAlipayAf",

          "reTotal",

          "deWeChatBefore",

          "deAlipayBefore",

          "deWeChatBe",

          "deAlipayBe",

          "deWeChatTe",

          "deAlipayTe",

          "deWeChatAf",

          "deAlipayAf",

          "deTotal"

        ];

        let list = this.capitalStatementData;

        // table数据转换

        const data = this.formatJson(filterVal, list);

        //进行所有表头的单元格合并,建议一行一行来,不然容易整乱

        const merges = [

          "A1:A3",

          "B1:E1",

          "B2:B3",

          "C2:C3",

          "D2:D3",

          "E2:E3",

          "F1:N1",

          "F2:G2",

          "H2:I2",

          "J2:K2",

          "L2:M2",

          "N2:N3",

          "O1:W1",

          "O2:P2",

          "Q2:R2",

          "S2:T2",

          "U2:V2",

          "W2:W3"

        ];

        // 导出excel表,的标题

        const defaultTitle = "各企业资金统计";

        // 按照顺序传参

        excel.export_json_to_excel(

          multiHeader, //这里是第一行的表头

          multiHeader2, //这里是第二行的表头

          tHeader, //这里应该是算第三行的表头

          data, // 表格数据

          defaultTitle, // excel表的名称

          merges // 合并excel单元格

        );

      );

    ,

    /* 转换table数据,以便正确导出数据

    -------------------------------------------------------------------*/

    formatJson(filterVal, jsonData) 

      return jsonData.map(v =>

        filterVal.map(j => 

          if (j !== "companyName") 

            return parseTime(v[j]);

           else 

            return v[j];

          

        )

      );

    ,

进阶Ant-Design-Vue你知道table多级表头嵌套展开写法吗?

目录

文章目录

目录

文章目录

前言

一、嵌套多级表头

(一)、写法一(标签展开)

(二)、写法二(头尾分离)

二、单选、全选控制

三、完整代码:

四、总结

(1)关于a-checkbox

(2)关于a-table

参考


 

前言:

Ant-Design-Vue的前端项目中,我们会经常处理表格,表单这些组件元素,熟练运用并知道它们在使用过程中的联系与区别,这是一个前端必不可少的哟。本文我旨在解决两个问题:

(1)如何便于更好的嵌套多级表头

(2)如何通过a-checkbox控制全选,单选显示a-table对应的列元素

类似于ElementUI,Ant-Design-vue中有很多相似点,但又不完全苟同,有很多自己独有的写法和思想。相信很多人都是先入手ElementUI,再入手Ant,这其实是对开发者比较友好的方式,如果你熟练掌握前者,后者也会很快上手。无需多言,咱们开整!

一、嵌套多级表头

效果如下:

(一)、写法一(标签展开)

先写HTML,用Ant的a-table-column-group去嵌套有合并单元格的列元素,没有合并单元格的就用a-table-column。先绘制全选、单选框:


<a-col :span="24">
    <div style="margin: 10px 0;">
        <a-checkbox :indeterminate="indeterminate" :checked="checkAll"@change="handleTagCheckAllChange">全选</a-checkbox>
        <!-- 勾选复选框 -->
        <a-checkbox-group :value="checkValue" :options="colOptions"/>
    </div> 
</a-col>

然后,展开table部分:

<a-table :rowClassName="rowClassName" :dataSource="data" bordered :pagination="false" x="true" :locale="{emptyText: '暂无数据'}" :scroll='{x:1300, y: scrollHeight - 270}' >
    <a-table-column dataIndex="devicename"  key="devicename" :width="160" :ellipsis="true" align="center" title="名称" fixed="left"></a-table-column>
    <a-table-column-group v-if="colIsTrue[0]" title="状态" align="center"> 
        <a-table-column title="运行状态" key="runstatus" :width="140" dataIndex="runstatus" align="center"></a-table-column>
    </a-table-column-group>
    <a-table-column-group v-if="colIsTrue[1]" title="压力 Mpa" align="center">
        <a-table-column title="高值" key="ia" :width="100" dataIndex ='ia' align="center" ></a-table-column>
        <a-table-column title="中值" key="ib" :width="100" dataIndex ='ib' align="center" ></a-table-column>
        <a-table-column title="低值" key="ic" :width="100" dataIndex ='ic' align="center" ></a-table-column>
    </a-table-column-group>
</a-table>

其次是js中定义静态的数据:

data是表格内容的数据,现在外面定义一个全局的数组data,键值就是和table中的key一 一对应, return中直接使用:

const data = [
        {
            key: 1,
            devicename: "模板1",
            runstatus: "正常",
            ia: "0.5",
            ib: "0.1",
            ic: "0.2",
            pa: "100",
            pb: "100",
            pc: "120",
            p: "110",
            qa: "200",
            qb: "300",
            qc: "400",
            q: "500",
            s: "220",
        }
    ];

定义用到的变量,防止运行报错:

scrollHeight: window.innerHeight - 160,
checkAll: true,
indeterminate: false,
data,
colIsTrue: [],
checkValue:[],
colOptions:[
    {label:'状态',value:0,onChange:this.colChange},
    {label:'压力',value:1,onChange:this.colChange},
    {label:'功率',value:2,onChange:this.colChange},
],

在methods中定义一个rowClassName方法,用于修改表头的颜色:

//修改表头颜色
rowClassName(record,index) {
    let tableBack = "table-back"
    return tableBack;
},

(二)、写法二(头尾分离)

先写好布局,相对来说布局更简洁:

<a-col :span="24">
    <div style="margin: 10px 0;">
        <a-checkbox :indeterminate="indeterminate" :checked="checkAll" @change="handleTagCheckAllChange">全选</a-checkbox>
        <a-checkbox-group v-model="checkedTagList" :options="varTagOptions" @change="handleTagChange"/>
    </div>
</a-col>
<a-table :rowClassName="rowClassName" :columns="columns" :data-source="data" bordered :pagination="false" :scroll="{ x: 1300, y: scrollHeight - 270 }">
</a-table>

其次先定义外部数据columns和data(同上):

const columns = [
        {
            title: '设备名称',
            dataIndex: 'devicename',
            key: 'devicename',
            align: 'center',
            width: 200,
            fixed: 'left'
        },
        {
            title: '状态',
            align: 'center',
            isShow: true,//控制列元素是否显示
            children: [
                {
                    title: '运行状态',
                    dataIndex: 'runstatus',
                    key: 'runstatus',
                    align: 'center',
                    width: 120,
                    // scopedSlots: {customRender: 'runstatus'}
                },
            ]
        },
        {
            title: '压力 Mpa',
            isShow: true,//控制列元素是否显示
            children: [
                {
                    title: '高压',
                    dataIndex: 'ia',
                    key: 'ia',
                    width: 120,
                    align: 'center'
                },
                {
                    title: '中压',
                    dataIndex: 'ib',
                    key: 'ib',
                    width: 120,
                    align: 'center'
                },
                {
                    title: '低压',
                    dataIndex: 'ic',
                    key: 'ic',
                    width: 120,
                    align: 'center'
                }
            ]
        },
        {
            title: '功率',
            isShow: true,//控制列元素是否显示
            children: [
                {
                    title: 'A相有功 kW',
                    dataIndex: 'pa',
                    key: 'pa',
                    width: 160,
                    align: 'center'
                },
                {
                    title: 'B相有功 kW',
                    dataIndex: 'pb',
                    key: 'pb',
                    width: 160,
                    align: 'center'
                },
                {
                    title: 'C相有功 kW',
                    dataIndex: 'pc',
                    key: 'pc',
                    width: 160,
                    align: 'center'
                },
                {
                    title: '有功功率 kW',
                    dataIndex: 'p',
                    key: 'p',
                    width: 160,
                    align: 'center'
                },
                {
                    title: 'A相无功 kVar',
                    dataIndex: 'qa',
                    key: 'qa',
                    width: 160,
                    align: 'center'
                },
                {
                    title: 'B相无功 kVar',
                    dataIndex: 'qb',
                    key: 'qb',
                    width: 160,
                    align: 'center'
                },
                {
                    title: 'C相无功 kVar',
                    dataIndex: 'qc',
                    key: 'qc',
                    width: 160,
                    align: 'center'
                },
                {
                    title: '无功功率 kVar',
                    dataIndex: 'q',
                    key: 'q',
                    width: 160,
                    align: 'center'
                },
                {
                    title: '视在功率 kVA',
                    dataIndex: 's',
                    key: 's',
                    width: 160,
                    align: 'center'
                }
            ]
        },
    ];

定义return数据源变量:

scrollHeight: window.innerHeight - 160,
checkAll: true,
indeterminate: false,
columns,
data,
colIsTrue: [],
checkValue:[],
colOptions:[
    {label:'状态',value:0,onChange:this.colChange},
    {label:'压力',value:1,onChange:this.colChange},
    {label:'功率',value:2,onChange:this.colChange},
],

还是在methods中定义一个方法,修改表头颜色(同上):

//修改表头颜色
rowClassName(record,index) {
    let tableBack = "table-back"
    return tableBack;
},

二、单选、全选控制

上面的准备工作基本做完了,下面的是和标签展开写法一是搭配用的 ,我们要进行处理js:

先对单选勾选框处理:

colChange(e){
    const index = e.target.value;
    // this.colIsTrue[index] ? (this.$set(this.colIsTrue,index,false)) : (this.$set(this.colIsTrue,index,true))
    if(e.target.checked) {
        this.checkValue.push(index);  this.$set(this.colIsTrue, index, true);
    } else{
        this.$set(this.colIsTrue, index, false);
        this.checkValue.forEach((item,arrIndex)=>{
            if(item==index){
                this.checkValue.splice(arrIndex,1)
            }
        })
    }
},

再处理全选复选框:

handleTagCheckAllChange(e) { 
    if(e.target.checked){
        let arrChange = [];
        for(let item of this.colOptions){ 
            arrChange.push(item.value);
        }
        this.checkValue = arrChange;
        this.colIsTrue.forEach((item, index) => {
            this.$set(this.colIsTrue, index, true);
        })
    }else{
        this.checkValue = [];
        this.colIsTrue.forEach((item, index) => {
            this.$set(this.colIsTrue, index, false);
        })
    }
    this.checkAll = e.target.checked;//全选的状态
    this.indeterminate = false;
},

最后钩子函数created和mounted中加入:

created() {
    this.checkValue = [];
    当所有数据都加载完成之后,将checkbox设置为全部选中状态
    this.colOptions && this.colOptions.forEach((item,index)=>{
        this.colIsTrue.push(true)
        this.checkValue.push(index)
    })
},

mounted() {
    this.checkValue = [];
    this.colOptions && this.colOptions.forEach((item,index)=>{
        this.colIsTrue.push(true)
        this.checkValue.push(index) 
    })
},

三、完整代码:

<template>
<div>
  <a-row>
    <a-col :span="24">
        <div style="margin: 10px 0;">
            <a-checkbox :indeterminate="indeterminate" :checked="checkAll"@change="handleTagCheckAllChange">全选</a-checkbox>
            <!-- 勾选复选框 -->
            <a-checkbox-group :value="checkValue" :options="colOptions"/>
        </div> 
     </a-col>
  </a-row>
  <a-table :rowClassName="rowClassName" :dataSource="data" bordered :pagination="false" x="true" :locale="{emptyText: '暂无数据'}" :scroll='{x:1300, y: scrollHeight - 270}' >
    <a-table-column dataIndex="devicename"  key="devicename" :width="160" :ellipsis="true" align="center" title="名称" fixed="left"></a-table-column>
    <a-table-column-group v-if="colIsTrue[0]" title="状态" align="center"> 
        <a-table-column title="运行状态" key="runstatus" :width="140" dataIndex="runstatus" align="center"></a-table-column>
    </a-table-column-group>
    <a-table-column-group v-if="colIsTrue[1]" title="压力 Mpa" align="center">
        <a-table-column title="高值" key="ia" :width="100" dataIndex ='ia' align="center" ></a-table-column>
        <a-table-column title="中值" key="ib" :width="100" dataIndex ='ib' align="center" ></a-table-column>
        <a-table-column title="低值" key="ic" :width="100" dataIndex ='ic' align="center" ></a-table-column>
    </a-table-column-group>
    <a-table-column-group v-if="colIsTrue[2]" title="功率 kW" align="center" >
        <a-table-column title="A相有功 kW" key="pa" dataIndex ='pa' :width="150" align='center'></a-table-column>
        <a-table-column title="B相有功 kW" key="pb" dataIndex ='pb' :width="150" align='center'></a-table-column>
        <a-table-column title="C相有功 kW" key="pc" dataIndex ='pc' :width="150" align='center'></a-table-column>
        <a-table-column title="有功功率 kW" key="p" dataIndex ='p' :width="150" align='center'></a-table-column>
        <a-table-column title="A相无功 kVar" key="qa" dataIndex ='qa' :width="150" align='center'></a-table-column>
        <a-table-column title="B相无功 kVar" key="qb" dataIndex ='qb' :width="150" align='center'></a-table-column>
        <a-table-column title="C相无功 kVar" key="qc" dataIndex ='qc' :width="150" align='center'></a-table-column>
        <a-table-column title="无功功率 kVar" key="q" dataIndex ='q' :width="150" align='center'></a-table-column>
        <a-table-column title="视在功率 kVA" key="s" dataIndex ='s' :width="150" align='center'></a-table-column>
    </a-table-column-group>
 </a-table>
</div>
</template>
<script>
    import moment from 'moment';
    const data = [
        {
            key: 1,
            devicename: "模板1",
            runstatus: "正常",
            ia: "0.5",
            ib: "0.1",
            ic: "0.2",
            pa: "100",
            pb: "100",
            pc: "120",
            p: "110",
            qa: "200",
            qb: "300",
            qc: "400",
            q: "500",
            s: "220",
        },{
            key: 2,
            devicename: "模板2",
            runstatus: "异常",
            ia: "0.5",
            ib: "0.1",
            ic: "0.2",
            pa: "100",
            pb: "100",
            pc: "120",
            p: "110",
            qa: "200",
            qb: "300",
            qc: "400",
            q: "500",
            s: "220",
        }
    ];
    
    export default {
        data() {
           return {
                scrollHeight: window.innerHeight - 160,
                checkAll: true,
                indeterminate: false,
                data,
                colIsTrue: [],
                checkValue:[],
                colOptions:[
                    {label:'状态',value:0,onChange:this.colChange},
                    {label:'压力',value:1,onChange:this.colChange},
                    {label:'功率',value:2,onChange:this.colChange},
                ],
           }
        },

        methods: {

            //修改表头颜色
            rowClassName(record,index) {
                let tableBack = "table-back"
                return tableBack;
            },
            
            //*全选复选框
            handleTagCheckAllChange(e) { 
                if(e.target.checked){
                    let arrChange = [];
                    for(let item of this.colOptions){ 
                        arrChange.push(item.value);
                    }
                    this.checkValue = arrChange;
                    this.colIsTrue.forEach((item, index) => {
                        this.$set(this.colIsTrue, index, true);
                    })
                }else{
                    this.checkValue = [];
                    this.colIsTrue.forEach((item, index) => {
                        this.$set(this.colIsTrue, index, false);
                    })
                }
                this.checkAll = e.target.checked;//全选的状态
                this.indeterminate = false;
            },

            //单个选择勾选
            colChange(e){
                const index = e.target.value;
                // this.colIsTrue[index] ? (this.$set(this.colIsTrue,index,false)) : (this.$set(this.colIsTrue,index,true))
                if(e.target.checked) {
                    this.checkValue.push(index);  this.$set(this.colIsTrue, index, true);
                }
                else{
                    this.$set(this.colIsTrue, index, false);
                    this.checkValue.forEach((item,arrIndex)=>{
                        if(item==index){
                            this.checkValue.splice(arrIndex,1)
                        }
                    })
                }
            },
            
        },
        
        created(){
            this.checkValue = [];
            //测试*当所有数据都加载完成之后,将checkbox设置为全部选中状态
            this.colOptions && this.colOptions.forEach((item,index)=>{
                this.colIsTrue.push(true)
                this.checkValue.push(index)
            })
        },

        mounted() {
            this.checkValue = [];
            this.colOptions && this.colOptions.forEach((item,index)=>{
                this.colIsTrue.push(true)
                this.checkValue.push(index) 
            })
        },
    }
</script>

四、总结

(还是自己看下面的官方文档吧,官方的都是精髓)

(1)关于a-checkbox

Checkbox 

参数说明类型默认值版本
autoFocus自动获取焦点booleanfalse 
checked指定当前是否选中booleanfalse 
defaultChecked初始是否选中booleanfalse 
disabled失效状态booleanfalse 
indeterminate设置 indeterminate 状态,只负责样式控制booleanfalse

事件 #

事件名称说明回调参数版本
change变化时回调函数Function(e:Event)-

Checkbox Group #

参数说明类型默认值版本
defaultValue默认选中的选项string[][] 
disabled整组失效booleanfalse 
nameCheckboxGroup 下所有 input[type="checkbox"] 的 name 属性string-1.5.0
options指定可选项,可以通过 slot="label" slot-scope="option" 定制labelstring[] | Array<{ label: string value: string disabled?: boolean, indeterminate?: boolean, onChange?: function }>[] 
value指定选中的选项string[][] 

事件 #

事件名称说明回调参数版本
change变化时回调函数Function(checkedValue)

方法 #

Checkbox #

名称描述版本
blur()移除焦点 
focus()获取焦点

(2)关于a-table

参考:

【1】Ant-Design-Vue文档

【2】Vue动态控制表格列的显示隐藏

以上是关于vue 导出多级表头table 数据到excel的主要内容,如果未能解决你的问题,请参考以下文章

easypoi多级表头多个sheet导出,动态导出列

easypoi多级表头多个sheet导出,动态导出列

vue element-ui动态渲染多级table表头

vue xlsx组件 导出的excel表头插入内容

EasyExcel导出excel合并表头和数据

EasyExcel导出excel合并表头和数据