65.9K
CodeProject 正在变化。 阅读更多。
Home

JavaScript 生成 Excel 文件,简单方法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.19/5 (12投票s)

2017 年 7 月 20 日

CPOL

6分钟阅读

viewsIcon

107675

downloadIcon

1855

一个前端库,用于创建 Excel 文件,包括单元格的格式化和样式设置

引言

很多时候,我们需要将 Web 应用程序中的数据导出为 Excel 格式。通常,我们在浏览器中已经有了这些数据:作为表格内容的一部分,或者作为某个模型的一个实例……用户已经审阅过,对它感到满意,并希望在 Excel 中打开。在这种情况下,开发者有不同的选择

  • 什么都不做,甚至不提供该选项。在这种情况下,用户被迫直接从浏览器中选择数据,然后将其复制粘贴到 Excel 中。
  • 后端,在服务器上生成 Excel 文件。我敢肯定,无论你使用何种后端(.NET、Java、Node.js、PHP 等),都有许多库可以生成精美的 Excel 文件。
  • 前端,直接在浏览器中生成 Excel。

“什么都不做”的方法大多数时候是可行的,但通常结果会很糟糕。所有单元格格式都会在过程中丢失,同一行中的多个单元格会合并……

后端方法是最流行的。现有的库使得实现此功能快速且成本低廉。但是,存在一些缺点,这些缺点可能会或可能不会影响你

  1. 它使用了服务器资源,这在高负载系统上可能会成为一个问题。
  2. 存在“延迟”,浏览器必须将“生成我的 Excel”请求发送到服务器,服务器必须生成它,然后将其发送回浏览器进行下载。这会导致用户按下“导出为 Excel”按钮和实际文件下载之间出现明显的“延迟”
  3. 通常,后端需要访问前端已有的相同数据。对于持久性数据,我们需要数据库查询、服务器上实现的数据缓存……或者浏览器连同“生成 Excel 请求”一起发送要包含的数据。所有这些都会增加后端的工作负载、网络流量和上述延迟。

使用前端方法,所有先前的问题都会消失。通常这非常快,因为根本不需要网络。然而,可用的库数量相当少,并且通常存在某种权衡。

一方面,我们有一些库不生成真正的 Excel,而是生成 Excel 可以打开的其他格式(XML、CSV 等)。如果你只需要纯数据导出,而不需要 Excel 的任何特定功能(多于一个工作表、单元格格式等),它们就足够了。

关于生成真正 Excel 的库,它们要么是功能有限的小型库(例如:完全没有单元格格式),要么是提供全范围 Excel 功能的大型库(`js-xlsx`、`exceljs`、`openxmlsdkjs` 等),并且通常有巨大的文档。

在本文中,我介绍了一个小型库,它以一种清晰简洁的方式呈现了最基本的功能。尽管如此,这正是我在 90% 的 Excel 生成需求中所需要的功能。

Using the Code

该库旨在在浏览器中使用,因此它是一个 JavaScript 库,有两个依赖项

  1. JSZip v3.1.3 by Stuart Knightley, http://stuartk.com/jszip
  2. FileSaver.js by Eli Grey, http://eligrey.com

要使用它,我们只需将其包含在我们的 `` 标签中

<script type="text/javascript" src="jszip.js"></script>
<script type="text/javascript" src="FileSaver.js"></script>
<script type="text/javascript" src="myexcel.js"></script>

该库定义了一个全局对象 `$JExcel`。该对象包含一些通用转换和一个 Excel 对象生成器。

var excel = $JExcel.new();                    // Create an Excel with system default font
var excel = $JExcel.new("Arial 10 #333333");  // Default font is Arial 10 in RGB #333

Excel 对象定义了四个方法

  • addSheet
  • addStyle
  • set
  • generate

``addSheet`` 用于向 Excel 对象添加额外的工作表。它需要一个名称。Excel 对象始终有一个默认工作表(索引 0)。工作表通过其创建索引进行引用。

``addStyle`` 用于在 Excel 文档中注册样式。它需要一个样式定义对象,该对象最多包含 5 个属性

{
  fill: "#ECECEC" ,                        // background color in #RRGGBB
  border: "none,none,none,thin #333333"    // left border,right border,top border, bottom border
  font: "Calibri 12 #0000AA B"});          // font-name font-size font-color font-style
  format: "yyyy.mm.dd hh:mm:ss",           // display format
  align: "R T",                            // horizontal-align vertical-align
}

边框定义由“边框样式”和“RGB 边框颜色”组成。允许的边框样式可在 `$JExcel.borderStyles` 数组中找到。

如果 `font-style` 包含 **B** 字符,则字体为粗体,**U** 表示下划线,**I** 表示斜体。

在 `$JExcel.formats` 数组中有许多预定义的显示格式。也可以自定义它们。

对于水平对齐和垂直对齐,应用以下约定:C:居中 L:左 R:右 T:顶部 B:底部 -:无。

``set`` 用于在单元格/行/列/工作表上设置值或样式。设置的内容由非 `undefined` 的参数决定。适用以下规则

  1. 如果仅定义了工作表索引,则设置工作表名称
  2. 如果仅定义了工作表索引和行号,则可以为该工作表中的行设置样式,并为行高设置值
  3. 如果仅定义了工作表索引和列号,则可以为该工作表中的列设置样式,并为列宽设置值
  4. 如果定义了工作表索引、列号和行号,则可以为定义的单元格设置样式,并为其内容设置值

``set`` 方法允许使用规范列表参数,或单个对象参数。在规范形式中,将 `undefined` 用作不应用的值;在对象参数中,只需不包含该属性。

set(0,undefined,undefined,"Summary");                      // Set name of SHEET 0 to Summary

var fillEC=excel.addStyle ( {fill: "#ECECEC"});            // Style in ECECEC background color
set(2,undefined,1,undefined,fillEC);                       // Set fillEC style in row 1 in sheet 2
set( {sheet:2,row:1,style:fillEC});                        // alternatively

var Arial10B=excel.addStyle ({font: "Arial 10 B"});        // Define style Arial 10 bold                
set( {sheet:0,col:5,row:3,value: "HELLO",style:Arial10B}); // Set HELLO in col 5 and row 3 in sheet 0 
set(0,5,3,"HELLO",Arial10B);                               // alternatively 

``generate`` 方法生成一个 Excel 工作簿并使其可供下载。

关注点

XLSX 格式只是一堆 zip 在一起的 XML 文件。这些 XML 文件遵循 OpenXML 约定。该库通过定义 Excel 对象模型(工作表、行、单元格、样式……)并在内存中进行设置来工作,当调用 **`generate`** 方法时,会创建 Excel 对象所需的 XML 节点。

然后,“打印”这些 XML 节点并与 OpenXML 模板合并,然后将所有内容 zip 起来,生成的流即可下载。

Excel 不像 JavaScript 那样处理日期时间。它们使用不同的 EPOCH 时刻。该库定义了以下转换函数 `$JExcel.toExcelLocalTime(jsDate)`、`$JExcel.toExcelUTCTime(jsDate)`

为了处理 RGB 值,还提供了以下函数 `$JExcel.rgbToHex(red,green,blue)`。

示例

以下示例……

function randomDate(start, end) {
    var d= new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime()));
    return d;
}
        
var excel = $JExcel.new("Calibri light 10 #333333");            
excel.set( {sheet:0,value:"This is Sheet 0" } );
var evenRow=excel.addStyle( { border: "none,none,none,thin #333333"});        
var oddRow=excel.addStyle ( { fill: "#ECECEC" ,border: "none,none,none,thin #333333"}); 
for (var i=1;i<50;i++) excel.set({row:i,style: i%2==0 ? evenRow: oddRow  });  
excel.set({row:3,value: 30  });                    
 
var headers=["Header 0","Header 1","Header 2","Header 3","Header 4"];                            
var formatHeader=excel.addStyle ( {
    border: "none,none,none,thin #333333",font: "Calibri 12 #0000AA B"}
);                                                         

for (var i=0;i<headers.length;i++){              // Loop headers
    excel.set(0,i,0,headers[i],formatHeader);    // Set CELL header text & header format
    excel.set(0,i,undefined,"auto");             // Set COLUMN width to auto 
}
            
var initDate = new Date(2000, 0, 1);
var endDate = new Date(2016, 0, 1);
var dStyle = excel.addStyle ( {                       
    align: "R",                                                                                
    format: "yyyy.mm.dd hh:mm:ss",                                                             
    font: "#00AA00"}
);                                                                         
            
for (var i=1;i<50;i++){                                    // Generate 50 rows
    excel.set(0,0,i,"This is line "+i);                    // This column is a TEXT
    var d=randomDate(initDate,endDate);                    // Get a random date
    excel.set(0,1,i,d.toLocaleString());                   // Random date as STRING
    excel.set(0,2,i,$JExcel.toExcelLocalTime(d));          // Date as a NUMERIC
    excel.set(0,3,i,$JExcel.toExcelLocalTime(d),dStyle);   // Date as a NUMERIC in dStyle.format
    excel.set(0,4,i,"Some other text");                    // Some other text
}

excel.set(0,1,undefined,30);                               // Set COLUMN B to 30 chars width
excel.set(0,3,undefined,30);                               // Set COLUMN D to 20 chars width
excel.set(0,4,undefined,20, excel.addStyle( {align:"R"})); // Align column 4 to the right
excel.set(0,1,3,undefined,excel.addStyle( {align:"L T"})); // CELL B4  to LEFT-TOP
excel.set(0,2,3,undefined,excel.addStyle( {align:"C C"})); // CELL C4  to CENTER-CENTER
excel.set(0,3,3,undefined,excel.addStyle( {align:"R B"})); // CELL D4  to RIGHT-BOTTOM
excel.generate("SampleData.xlsx");

……生成以下 Excel 工作簿

请注意 B、C 和 D 列的不同显示,它们基本上包含相同的数据,但格式不同。此外,第 4 行中所有列的大小和单元格对齐方式的差异也很明显。

公式

要使用公式,只需像在 Excel 中一样输入即可

excel.set(0,8,1,15);            // Grid position 8,1 references cell I2    
excel.set(0,8,2,13);            // Grid position 8,2 references cell I3
excel.set(0,8,3,"=I2+I3");      // In cell I4: I2+I3 => 15+13 => 28

最后

实现这个转换器比预期的要容易。代码简短且注释良好,并且应该易于修改以添加新功能(例如,单元格合并)。你可以在 http://jsegarra1971.github.io/MyExcel/sample.html 找到演示,并且最新的代码可在 https://github.com/jsegarra1971/MyExcel 获取

如果你使用它,请告诉我!!!

© . All rights reserved.