zoukankan      html  css  js  c++  java
  • 【js-xlsx和file-saver插件】前端html的table导出数据到excel的表格合并显示boder

    最近在做项目,需要从页面的表格中导出excel,一般导出excel有两种方法:一、习惯上是建模版从后台服务程序中导出;二、根据页面table中导出;综合考虑其中利弊选择二、根据页面table中导出excel,前段有用table的也有用vue的,结佣file-saver和xlsx插件进行导出excel。

    没有做封装,直接改的源码

      /* generate workbook object from table */
                    var defaultCellStyle = { font: { name: 'Times New Roman', sz: 16, color: { rgb: "#FF000000" }, bold: false, italic: false, underline: false }, alignment: { vertical: "center", horizontal: "center", indent: 0, wrapText: true }, border: { top: { style: "thin", color: { "auto": 1 } }, right: { style: "thin", color: { "auto": 1 } }, bottom: { style: "thin", color: { "auto": 1 } }, left: { style: "thin", color: { "auto": 1 } } } };
                    var cell = {defaultCellStyle: defaultCellStyle};
                    var wb = XLSX.utils.table_to_book(document.querySelector('.el-table__fixed'),cell)
                    /* get binary string as output */
                    
                    //设置表格的样式
                    var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: false, type: 'binary',cellStyles: true, defaultCellStyle: defaultCellStyle, showGridLines: true }); 
                    var s2ab=function(s) {
                        let buf = new ArrayBuffer(s.length);
                        let view = new Uint8Array(buf);
                        for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
                        return buf;
                    };
    saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), '报表.xlsx')


    页面中需要引入文件

     <script type="text/javascript" src="shim.min.js"></script>
        <script type="text/javascript" src="jszip.js"></script>
        <script type="text/javascript" src="xlsx.full.js"></script>
        <script type="text/javascript" src="Blob.js"></script>
        <script type="text/javascript" src="FileSaver.js"></script>

    此处的xlsx.full.js是由https://github.com/SheetJS/js-xlsx下载的源文件修改的

    修改主要参考了https://github.com/xSirrioNx资源

      1 var StyleBuilder = function (options) {
      2 
      3     var customNumFmtId = 164;
      4 
      5 
      6     var table_fmt = {
      7         0: 'General',
      8         1: '0',
      9         2: '0.00',
     10         3: '#,##0',
     11         4: '#,##0.00',
     12         9: '0%',
     13         10: '0.00%',
     14         11: '0.00E+00',
     15         12: '# ?/?',
     16         13: '# ??/??',
     17         14: 'm/d/yy',
     18         15: 'd-mmm-yy',
     19         16: 'd-mmm',
     20         17: 'mmm-yy',
     21         18: 'h:mm AM/PM',
     22         19: 'h:mm:ss AM/PM',
     23         20: 'h:mm',
     24         21: 'h:mm:ss',
     25         22: 'm/d/yy h:mm',
     26         37: '#,##0 ;(#,##0)',
     27         38: '#,##0 ;[Red](#,##0)',
     28         39: '#,##0.00;(#,##0.00)',
     29         40: '#,##0.00;[Red](#,##0.00)',
     30         45: 'mm:ss',
     31         46: '[h]:mm:ss',
     32         47: 'mmss.0',
     33         48: '##0.0E+0',
     34         49: '@',
     35         56: '"上午/下午 "hh"時"mm"分"ss"秒 "'
     36     };
     37     var fmt_table = {};
     38 
     39     for (var idx in table_fmt) {
     40         fmt_table[table_fmt[idx]] = idx;
     41     }
     42 
     43 
     44     // cache style specs to avoid excessive duplication
     45     _hashIndex = {};
     46     _listIndex = [];
     47 
     48     return {
     49 
     50         initialize: function (options) {
     51 
     52             this.$fonts = XmlNode('fonts').attr('count', 0).attr("x14ac:knownFonts", "1");
     53             this.$fills = XmlNode('fills').attr('count', 0);
     54             this.$borders = XmlNode('borders').attr('count', 0);
     55             this.$numFmts = XmlNode('numFmts').attr('count', 0);
     56             this.$cellStyleXfs = XmlNode('cellStyleXfs');
     57             this.$xf = XmlNode('xf')
     58                 .attr('numFmtId', 0)
     59                 .attr('fontId', 0)
     60                 .attr('fillId', 0)
     61                 .attr('borderId', 0);
     62 
     63             this.$cellXfs = XmlNode('cellXfs').attr('count', 0);
     64             this.$cellStyles = XmlNode('cellStyles')
     65                 .append(XmlNode('cellStyle')
     66                     .attr('name', 'Normal')
     67                     .attr('xfId', 0)
     68                     .attr('builtinId', 0)
     69                 );
     70             this.$dxfs = XmlNode('dxfs').attr('count', "0");
     71             this.$tableStyles = XmlNode('tableStyles')
     72                 .attr('count', '0')
     73                 .attr('defaultTableStyle', 'TableStyleMedium9')
     74                 .attr('defaultPivotStyle', 'PivotStyleMedium4')
     75 
     76 
     77             this.$styles = XmlNode('styleSheet')
     78                 .attr('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006')
     79                 .attr('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac')
     80                 .attr('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main')
     81                 .attr('mc:Ignorable', 'x14ac')
     82                 .prefix('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>')
     83                 .append(this.$numFmts)
     84                 .append(this.$fonts)
     85                 .append(this.$fills)
     86                 .append(this.$borders)
     87                 .append(this.$cellStyleXfs.append(this.$xf))
     88                 .append(this.$cellXfs)
     89                 .append(this.$cellStyles)
     90                 .append(this.$dxfs)
     91                 .append(this.$tableStyles);
     92 
     93 
     94             // need to specify styles at index 0 and 1.
     95             // the second style MUST be gray125 for some reason
     96 
     97             var defaultStyle = options.defaultCellStyle || {};
     98             if (!defaultStyle.font) defaultStyle.font = { name: 'Calibri', sz: '12' };
     99             if (!defaultStyle.font.name) defaultStyle.font.name = 'Calibri';
    100             if (!defaultStyle.font.sz) defaultStyle.font.sz = 11;
    101             if (!defaultStyle.fill) defaultStyle.fill = { patternType: "none", fgColor: {} };
    102             if (!defaultStyle.border) defaultStyle.border = {};
    103             if (!defaultStyle.numFmt) defaultStyle.numFmt = 0;
    104 
    105             this.defaultStyle = defaultStyle;
    106 
    107             var gray125Style = JSON.parse(JSON.stringify(defaultStyle));
    108             gray125Style.fill = { patternType: "gray125", fgColor: {} }
    109 
    110             this.addStyles([defaultStyle, gray125Style]);
    111             return this;
    112         },
    113 
    114         // create a style entry and returns an integer index that can be used in the cell .s property
    115         // these format of this object follows the emerging Common Spreadsheet Format
    116         addStyle: function (attributes) {
    117 
    118             var hashKey = JSON.stringify(attributes);
    119             var index = _hashIndex[hashKey];
    120             if (index == undefined) {
    121 
    122                 index = this._addXf(attributes); //_listIndex.push(attributes) -1;
    123                 _hashIndex[hashKey] = index;
    124             }
    125             else {
    126                 index = _hashIndex[hashKey];
    127             }
    128             return index;
    129         },
    130 
    131         // create style entries and returns array of integer indexes that can be used in cell .s property
    132         addStyles: function (styles) {
    133             var self = this;
    134             return styles.map(function (style) {
    135                 return self.addStyle(style);
    136             })
    137         },
    138 
    139         _duckTypeStyle: function (attributes) {
    140 
    141             if (typeof attributes == 'object' && (attributes.patternFill || attributes.fgColor)) {
    142                 return { fill: attributes }; // this must be read via XLSX.parseFile(...)
    143             }
    144             else if (attributes.font || attributes.numFmt || attributes.border || attributes.fill) {
    145                 return attributes;
    146             }
    147             else {
    148                 return this._getStyleCSS(attributes)
    149             }
    150         },
    151 
    152         _getStyleCSS: function (css) {
    153             return css; //TODO
    154         },
    155 
    156         // Create an <xf> record for the style as well as corresponding <font>, <fill>, <border>, <numfmts>
    157         // Right now this is simple and creates a <font>, <fill>, <border>, <numfmts> for every <xf>
    158         // We could perhaps get fancier and avoid duplicating  auxiliary entries as Excel presumably intended, but bother.
    159         _addXf: function (attributes) {
    160 
    161 
    162             var fontId = this._addFont(attributes.font);
    163             var fillId = this._addFill(attributes.fill);
    164             var borderId = this._addBorder(attributes.border);
    165             var numFmtId = this._addNumFmt(attributes.numFmt);
    166 
    167             var $xf = XmlNode('xf')
    168                 .attr("numFmtId", numFmtId)
    169                 .attr("fontId", fontId)
    170                 .attr("fillId", fillId)
    171                 .attr("borderId", borderId)
    172                 .attr("xfId", "0");
    173 
    174             if (fontId > 0) {
    175                 $xf.attr('applyFont', "1");
    176             }
    177             if (fillId > 0) {
    178                 $xf.attr('applyFill', "1");
    179             }
    180             if (borderId > 0) {
    181                 $xf.attr('applyBorder', "1");
    182             }
    183             if (numFmtId > 0) {
    184                 $xf.attr('applyNumberFormat', "1");
    185             }
    186 
    187             if (attributes.alignment) {
    188                 var $alignment = XmlNode('alignment');
    189                 if (attributes.alignment.horizontal) {
    190                     $alignment.attr('horizontal', attributes.alignment.horizontal);
    191                 }
    192                 if (attributes.alignment.vertical) {
    193                     $alignment.attr('vertical', attributes.alignment.vertical);
    194                 }
    195                 if (attributes.alignment.indent) {
    196                     $alignment.attr('indent', attributes.alignment.indent);
    197                 }
    198                 if (attributes.alignment.readingOrder) {
    199                     $alignment.attr('readingOrder', attributes.alignment.readingOrder);
    200                 }
    201                 if (attributes.alignment.wrapText) {
    202                     $alignment.attr('wrapText', attributes.alignment.wrapText);
    203                 }
    204                 if (attributes.alignment.textRotation != undefined) {
    205                     $alignment.attr('textRotation', attributes.alignment.textRotation);
    206                 }
    207 
    208                 $xf.append($alignment).attr('applyAlignment', 1)
    209 
    210             }
    211             this.$cellXfs.append($xf);
    212             var count = +this.$cellXfs.children().length;
    213 
    214             this.$cellXfs.attr('count', count);
    215             return count - 1;
    216         },
    217 
    218         _addFont: function (attributes) {
    219 
    220             if (!attributes) {
    221                 return 0;
    222             }
    223 
    224             var $font = XmlNode('font')
    225                 .append(XmlNode('sz').attr('val', attributes.sz || this.defaultStyle.font.sz))
    226                 .append(XmlNode('name').attr('val', attributes.name || this.defaultStyle.font.name))
    227 
    228             if (attributes.bold) $font.append(XmlNode('b'));
    229             if (attributes.underline) $font.append(XmlNode('u'));
    230             if (attributes.italic) $font.append(XmlNode('i'));
    231             if (attributes.strike) $font.append(XmlNode('strike'));
    232             if (attributes.outline) $font.append(XmlNode('outline'));
    233             if (attributes.shadow) $font.append(XmlNode('shadow'));
    234 
    235             if (attributes.vertAlign) {
    236                 $font.append(XmlNode('vertAlign').attr('val', attributes.vertAlign))
    237             }
    238 
    239 
    240             if (attributes.color) {
    241                 if (attributes.color.theme) {
    242                     $font.append(XmlNode('color').attr('theme', attributes.color.theme))
    243 
    244                     if (attributes.color.tint) { //tint only if theme
    245                         $font.append(XmlNode('tint').attr('theme', attributes.color.tint))
    246                     }
    247 
    248                 } else if (attributes.color.rgb) { // not both rgb and theme
    249                     $font.append(XmlNode('color').attr('rgb', attributes.color.rgb))
    250                 }
    251             }
    252 
    253             this.$fonts.append($font);
    254 
    255             var count = this.$fonts.children().length;
    256             this.$fonts.attr('count', count);
    257             return count - 1;
    258         },
    259 
    260         _addNumFmt: function (numFmt) {
    261             if (!numFmt) {
    262                 return 0;
    263             }
    264 
    265             if (typeof numFmt == 'string') {
    266                 var numFmtIdx = fmt_table[numFmt];
    267                 if (numFmtIdx >= 0) {
    268                     return numFmtIdx; // we found a match against built in formats
    269                 }
    270             }
    271 
    272             if (/^[0-9]+$/.exec(numFmt)) {
    273                 return numFmt; // we're matching an integer against some known code
    274             }
    275             numFmt = numFmt
    276                 .replace(/&/g, '&amp;')
    277                 .replace(/</g, '&lt;')
    278                 .replace(/>/g, '&gt;')
    279                 .replace(/"/g, '&quot;')
    280                 .replace(/'/g, '&apos;');
    281 
    282             var $numFmt = XmlNode('numFmt')
    283                 .attr('numFmtId', (++customNumFmtId))
    284                 .attr('formatCode', numFmt);
    285 
    286             this.$numFmts.append($numFmt);
    287 
    288             var count = this.$numFmts.children().length;
    289             this.$numFmts.attr('count', count);
    290             return customNumFmtId;
    291         },
    292 
    293         _addFill: function (attributes) {
    294 
    295             if (!attributes) {
    296                 return 0;
    297             }
    298 
    299             var $patternFill = XmlNode('patternFill')
    300                 .attr('patternType', attributes.patternType || 'solid');
    301 
    302             if (attributes.fgColor) {
    303                 var $fgColor = XmlNode('fgColor');
    304 
    305                 //Excel doesn't like it when we set both rgb and theme+tint, but xlsx.parseFile() sets both
    306                 //var $fgColor = createElement('<fgColor/>', null, null, {xmlMode: true}).attr(attributes.fgColor)
    307                 if (attributes.fgColor.rgb) {
    308 
    309                     if (attributes.fgColor.rgb.length == 6) {
    310                         attributes.fgColor.rgb = "FF" + attributes.fgColor.rgb /// add alpha to an RGB as Excel expects aRGB
    311                     }
    312 
    313                     $fgColor.attr('rgb', attributes.fgColor.rgb);
    314                     $patternFill.append($fgColor);
    315                 }
    316                 else if (attributes.fgColor.theme) {
    317                     $fgColor.attr('theme', attributes.fgColor.theme);
    318                     if (attributes.fgColor.tint) {
    319                         $fgColor.attr('tint', attributes.fgColor.tint);
    320                     }
    321                     $patternFill.append($fgColor);
    322                 }
    323 
    324                 if (!attributes.bgColor) {
    325                     attributes.bgColor = { "indexed": "64" }
    326                 }
    327             }
    328 
    329             if (attributes.bgColor) {
    330                 var $bgColor = XmlNode('bgColor').attr(attributes.bgColor);
    331                 $patternFill.append($bgColor);
    332             }
    333 
    334             var $fill = XmlNode('fill')
    335                 .append($patternFill);
    336 
    337             this.$fills.append($fill);
    338 
    339             var count = this.$fills.children().length;
    340             this.$fills.attr('count', count);
    341             return count - 1;
    342         },
    343 
    344         _getSubBorder: function (direction, spec) {
    345 
    346             var $direction = XmlNode(direction);
    347             if (spec) {
    348                 if (spec.style) $direction.attr('style', spec.style);
    349                 if (spec.color) {
    350                     var $color = XmlNode('color');
    351                     if (spec.color.auto) {
    352                         $color.attr('auto', spec.color.auto);
    353                     }
    354                     else if (spec.color.rgb) {
    355                         $color.attr('rgb', spec.color.rgb);
    356                     }
    357                     else if (spec.color.theme || spec.color.tint) {
    358                         $color.attr('theme', spec.color.theme || "1");
    359                         $color.attr('tint', spec.color.tint || "0");
    360                     }
    361                    $direction.append($color)
    362                 }
    363             }
    364             return $direction;
    365         },
    366 
    367         _addBorder: function (attributes) {
    368             if (!attributes) {
    369                 return 0;
    370             }
    371 
    372             var self = this;
    373 
    374             var $border = XmlNode('border')
    375                 .attr("diagonalUp", attributes.diagonalUp)
    376                 .attr("diagonalDown", attributes.diagonalDown);
    377 
    378             var directions = ["left", "right", "top", "bottom", "diagonal"];
    379 
    380             directions.forEach(function (direction) {
    381                 $border.append(self._getSubBorder(direction, attributes[direction]))
    382             });
    383             this.$borders.append($border);
    384 
    385             var count = this.$borders.children().length;
    386             this.$borders.attr('count', count);
    387             return count - 1;
    388         },
    389 
    390         toXml: function () {
    391             return this.$styles.toXml();
    392         }
    393     }.initialize(options || {});
    394 }
     1 function get_cell_style(styles, cell, opts) {
     2     if (typeof style_builder != 'undefined') {
     3         if (/^d+$/.exec(cell.s)) {
     4             return cell.s
     5         }  // if its already an integer index, let it be
     6         if (cell.s && (cell.s == +cell.s)) {
     7             return cell.s
     8         }  // if its already an integer index, let it be
     9         var s = cell.s || {};
    10         if (cell.z) s.numFmt = cell.z;
    11         return style_builder.addStyle(s);
    12     }
    13     else {
    14         var z = opts.revssf[cell.z != null ? cell.z : "General"];
    15         var i = 0x3c, len = styles.length;
    16         if (z == null && opts.ssf) {
    17             for (; i < 0x188; ++i) if (opts.ssf[i] == null) {
    18                 SSF.load(cell.z, i);
    19                 opts.ssf[i] = cell.z;
    20                 opts.revssf[cell.z] = z = i;
    21                 break;
    22             }
    23         }
    24         for (i = 0; i != len; ++i) if (styles[i].numFmtId === z) return i;
    25         styles[len] = {
    26             numFmtId: z,
    27             fontId: 0,
    28             fillId: 0,
    29             borderId: 0,
    30             xfId: 0,
    31             applyNumberFormat: 1
    32         };
    33         return len;
    34     }
    35 }

    和我自己的以下的修改

     1 function parse_dom_table(table, _opts) {
     2         var opts = _opts || {};
     3         var oss = opts.defaultCellStyle||{};  /*单元格样式  */    
     4         if (DENSE != null) opts.dense = DENSE;
     5         var ws = opts.dense ? ([]) : ({});
     6         var rows = table.getElementsByTagName('tr');
     7         var sheetRows = Math.min(opts.sheetRows || 10000000, rows.length);
     8         var range = { s: { r: 0, c: 0 }, e: { r: sheetRows - 1, c: 0 } };
     9         var merges = [], midx = 0;
    10         var R = 0, _C = 0, C = 0, RS = 0, CS = 0;
    11         for (; R < sheetRows; ++R) {
    12             var row = rows[R];
    13             var elts = (row.children);
    14             for (_C = C = 0; _C < elts.length; ++_C) {
    15                 var elt = elts[_C], v = htmldecode(elts[_C].innerHTML);
    16                 for (midx = 0; midx < merges.length; ++midx) {
    17                     var m = merges[midx];
    18                     if (m.s.c == C && m.s.r <= R && R <= m.e.r)
    19                     {                       
    20                         C = m.e.c + 1; midx = -1;                      
    21                     }
    22                 }
    23                 /* TODO: figure out how to extract nonstandard mso- style */
    24                 CS = +elt.getAttribute("colspan") || 1;
    25                 if ((RS = +elt.getAttribute("rowspan")) > 0 || CS > 1)
    26                     merges.push({ s: { r: R, c: C }, e: { r: R + (RS || 1) - 1, c: C + CS - 1 } });
    27                 var o = { t: 's', v: v,s:oss};
    28                 var _t = elt.getAttribute("t") || "";
    29                 if (v != null) {
    30                     if (v.length == 0) o.t = _t || 's';
    31                     else if (opts.raw || v.trim().length == 0 || _t == "s") { }
    32                     else if (v === 'TRUE') o = { t: 'b', v: true, s: oss };
    33                     else if (v === 'FALSE') o = { t: 'b', v: false, s: oss };
    34                     else if (!isNaN(fuzzynum(v))) o = { t: 'n', v: fuzzynum(v), s: oss };
    35                     else if (!isNaN(fuzzydate(v).getDate())) {
    36                         o = ({ t: 'd', v: parseDate(v), s: oss });
    37                         if (!opts.cellDates) o = ({ t: 'n', v: datenum(o.v), s: oss });
    38                         o.z = opts.dateNF || SSF._table[14];
    39                     }
    40                 }
    41                 if (opts.dense) { if (!ws[R]) ws[R] = []; ws[R][C] = o; }
    42                 else ws[encode_cell({ c: C, r: R })] = o;
    43                 /* 合并数据处理开始*/
    44                 if (CS > 1) {
    45                     for (var i = 1; i < CS; i++) {
    46                         var newc = C + i
    47                         if (RS > 1) {
    48                             for (var m = 1; m < RS; m++) {
    49                                 var newr = R + m;
    50                                 ws[encode_cell({ c: newc, r: newr })] = o;
    51                             }
    52                         }
    53                         else {
    54                             ws[encode_cell({ c: newc, r: R })] = o;
    55                         }
    56                     }
    57                 }
    58                 else {
    59                     if (RS > 1) {
    60                         for (var m = 1; m < RS; m++) {
    61                             var newr = R + m;
    62                             ws[encode_cell({ c: C, r: newr })] = o;
    63                         }
    64                     }
    65                     else {
    66                         ws[encode_cell({ c: C, r: R })] = o;
    67                     }
    68                 }
    69                 /*合并数据处理结束*/
    70                 if (range.e.c < C) range.e.c = C;
    71                 C += CS;
    72                 
    73             }
    74         }
    75         ws['!merges'] = merges;
    76         ws['!ref'] = encode_range(range);
    77         if (sheetRows < rows.length) ws['!fullref'] = encode_range((range.e.r = rows.length - 1, range));
    78         return ws;
    79     }

    参考:

    https://github.com/SheetJS/js-xlsx
    https://github.com/xSirrioNx/js-xlsx
    https://www.jianshu.com/p/063badece350
    http://www.cnblogs.com/jtjds/p/8892510.html

  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/lilyshy/p/9006885.html
Copyright © 2011-2022 走看看