Excel complex table backend export is too complicated?

We can export Excel tables based on Dom in the front end

Pros: DOM-based styling, compatible with merged cells, and more

Disadvantage: It takes a long time to export all the data, because the DOM needs to be rendered

Browser support

picture

Install

Basic package

npm install xlsx

Style Enhancement Pack

npm install xlsx-style --save

Source code sample

Recommended version

 "xlsx": "^0.17.3",

 "xlsx-style": "^0.8.13"

< template > < div > < el-table :data = "tableData" :span-method = "arraySpanMethod" border style = "width: 100%" id = "tb" > < el-table-column prop = "id" label = "ID" width = "180" > </ el-table-column > < el-table-column prop = "name" label = "name"> </ el-table-column
 
   
     
     
     
     
     
   
     
      > < el-table-column prop = "amount1" sortable label = "number 1" > </ el-table-column > < el-table-column prop = "amount2" sortable label = "number 2" > </ el -table-column > < el-table-column prop = "amount3" sortable label = "value 3" > </ el-table-column > </ el-table >
     
     
     
     
     
     
   

   < button @click = "init()" > click me </ button > </ div > </ template >
 


< script >
import XLSX from "xlsx" ;
import * as XLSX2 from "xlsx-style" ;

export default { data () { return { tableData : [       { id : "12987122" , name : "Wang Xiaohu" , amount1 : "234" , amount2 : "3.2" , amount3 : 10 ,       },       { id : "12987123" , name : "Wang Xiaohu" , amount1 : "165" , amount2 : "4.43" ,amount3 :
 
   
     

         
         
         
         
         


         
         
         
         
         12 ,
      },
      { id : "12987124" , name : "Wang Xiaohu" , amount1 : "324" , amount2 : "1.9" , amount3 : 9 ,       },       { id : "12987125" , name : "Wang Xiaohu" , amount1 : "621" , amount2 : "2.2" , amount3 : 17 ,       },       { id :
         
         
         
         
         


         
         
         
         
         


         "12987126" , name : "Wang Xiaohu" , amount1 : "539" , amount2 : "4.1" , amount3 : 15 ,       },     ],   }; }, methods : { arraySpanMethod ({ row , column , rowIndex , columnIndex }) { if ( rowIndex % 2 === 0 ) { if ( columnIndex === 0 ) { return
         
         
         
         




 
   
     
       
         [ 1 , 2 ];
      } else if ( columnIndex === 1 ) { return [ 0 , 0 ];       }     }   },
         




   objectSpanMethod ({ row , column , rowIndex , columnIndex }) { if ( columnIndex === 0 ) { if ( rowIndex % 2 === 0 ) { return { rowspan : 2 , colspan : 1 ,         };       } else { return { rowspan : 0 , colspan : 0 ,         };       }
     
       
         
           
           


         
           
           


    }
  }, //Export init () { //Call the method of exporting Excel var fileName = "Test" ; var headLength = 5 ; //Get the number of columns in the table var colsLength = 1 ; //Get the number of rows in the table header , that is, at most several levels of table headers this . $nextTick (() => { this . excelTable ( "tb" , //table id `${ fileName }${ 20141212 }` , //Exported file name + time headLength , //There are several columns 6 ,
   
   
     
     
     
     
     
       
         
         
         
         //There are several lines in total colsLength //The header has several lines       );     });   }, //Recursively obtain the maximum number of layers in the header fcHeadLength ( header , headerRowLength ) { headerRowLength ++ ; header . forEach (( item ) => { if ( item . children && item . children . length > 0 ) { fcHeadLength ( item . children , headerRowLength );       }
         



   
   
     
     
       
         
else { if ( item . label !== "action" ) { headLength ++ ; if ( headerRowLength > colsLength ) { colsLength = headerRowLength ;           }         }
         
           
           
             



         return headLength ;
      }
    });
  }, //Export to Excel method tableToExcel ( tableID , fileName , headLength , colsLength , headColsLength ) { console . log ( tableID , fileName , headLength , colsLength , headColsLength ); var thwidth = []; / /Calculate cell length for ( let index = 0 ; index <
   
   
     
     
      headLength ; index ++ ) { //Calculate the header width var test = $ ( "thead" )         . find ( "tr:eq(0) th:eq(" + index + ")" )         . width (); thwidth .push ( test ); }     // return console . time ( "total export time" ); // add table style first, then download var sheet = XLSX . utils . table_to_sheet (
       
       


       

     
     
     
     
       document . querySelector ( `#${ tableID }` )
    ); //Convert a table object to a sheet object // console.log(sheet); var arr = []; //Get the collection of all column names for ( let i = 0 ; i < headLength ; i ++ ) { if ( i < 26 ) { arr . push ( String . fromCharCode ( 65 + i ). toUpperCase ());
     
     
     
       
         
      } else { // console.log(i, String.fromCharCode((65 + (i - 26))).toUpperCase()); arr . push ( "A" + String . fromCharCode ( 65 + ( i - 26 ) ). toUpperCase ());       }     } //The first layer of loop, loop column for ( let i = 0 ; i < arr . length ; i ++ ) { // Determine whether there are multi-level headers, multi-level headers , calculate the cell length of each column if ( headColsLength
         
         


     
     
       
        > 1 ) { //loop through multi-level headers for ( let j = 0 ; j < headColsLength ; j ++ ) { // only loop over existing headers if ( j < headColsLength && sheet [ arr [ i ] + j ] ) { // Determine the cell that is a multi-level header, calculate the cell length if ( ! sheet [ arr [ i ] + ( j + 1 )] || ! sheet [
         
         
           
           
             
             
               
               arr [ i ] + ( j - 1 )] ||
              ( ! sheet [ arr [ i ] + ( j - 1 )] && ! sheet [ arr [ i ] + ( j + 1 )])
            ) { //sheet[ "!cols"].push({ // wpx: sheet[arr[i] + j].v.length * 2 + 3, //});             }           }         }       } else
               
               
               



{ //It is not a multi-level header to directly calculate the cell length sheet [ "!cols" ]. push ({ wpx : thwidth [ i ],         });       } //The second layer of loop, loops each row of data in each column, Add text vertically centered for ( let k = 0 ; k < colsLength ; k ++ ) { if ( sheet [ arr [ i ] + k ]) { sheet [ arr [ i ] + k ] .s
         
         
           


       
       
         
            = { alignment : { horizontal : "center" , vertical : "center" , wrap_text : true ,             },           };         }       }     } console . timeEnd ( "Total export time" ); this . downloadExcel ( sheet2blob ( sheet ), ` ${ fileName }.xlsx` ); //Download // document.getElementById('app').removeChild(document.getElementById(tableID)) //After each download, delete the table generated by the download
             
               
               
               





     
     
     

     function sheet2blob ( sheet , sheetName ) { sheetName = sheetName || "sheet1" ; var workbook = { SheetNames : [ sheetName ], Sheets : {},       }; workbook . Sheets [ sheetName ] = sheet ; // Generate excel configuration items
       
       
         
         

       

       var wopts = { bookType : "xlsx" , // The type of file to be generated bookSST : false , // Whether to generate Shared String Table, the official explanation is that the generation speed will decrease if turned on, but it is better on low-version IOS devices Compatibility type : "binary" ,       }; var wbout = XLSX2 .write ( workbook , wopts ) ; var blob = new Blob ( [ s2ab ( wbout ) ] , { type : "application/octet-stream" ,       });
         
         
         

       
       
         
// String to ArrayBuffer function s2ab ( s ) { var buf = new ArrayBuffer ( s . length ); var view = new Uint8Array ( buf ); for ( var i = 0 ; i != s . length ; ++ i ) view [ i ] = s . charCodeAt ( i ) & 0xff ;
       
         
         
         
         return buf ;
      } return blob ;     }   }, downloadExcel ( url , saveName ) { if ( typeof url == "object" && url instanceof Blob ) { url = URL . createObjectURL ( url ); // create blob address     } var aLink = document . createElement ( "a" ); aLink . href =
       


   
     
       

     
      url ; aLink . download = saveName || "" ; // HTML5 new attribute, specify the save file name, you can do not need a suffix, note that it will not take effect in file:/// mode var event ; if ( window . MouseEvent ) event = new MouseEvent ( "click" ); else { event = document . createEvent ( "MouseEvents" ); event . initMouseEvent ( "click" , true , false , window
     
     
     
     
       
       
         
         
         
         , 0 , 0 , 0 , 0 , 0 , false , false , false , false , 0 , null       );     } aLink . dispatchEvent ( event );   }, excelTable ( tableID , fileName , headLength , colsLength , headColsLength ) { this . tableToExcel ( tableID , fileName ,
         
         
         
         
         
         
         
         
         
         
         


     

   
     
       
       
       headLength , colsLength + 1 , headColsLength     );   }, }, }; </ script >
       
       




Effect

picture