Excel现在可以使用js根据单元格数据生成图表和表格,或者使用js扩展自定义函数扩展内置Excel表达式。下面我们来了解一下ExceljsAPI的开放性是如何设计的,并从中学习一些开放API的设计经验。API文档:ExcelJavaScriptAPI概述精读Excel会使用JSAPI开放很多能力,包括用户可以通过界面轻松完成的能力,以及无法通过界面操作完成的能力。为什么打开JSAPIExcel已经具有很好的易用性,以及强大的公式公式。之前在精读《Microsoft Power Fx》中提到过,公式在Excel中是PowerFX,属于canvas低代码语言,但在Excel中称其为“公式”更为合适。既然你已经有这么多能力,为什么还需要JSAPI?总之,公式可以在JSAPI中使用,即JSAPI是公式能力的超集,包括Excel工作簿的增删改查、数据限制、RangeAreas操作、图表、数据透视表,甚至自动定义公式函数。也就是说,JSAPI让Excel“可编程”,即从开发者的角度对Excel进行二次扩展,包括公式的二次扩展,让Excel覆盖更多的场景。JSAPI可以用在什么地方?从Excel流程中最开始的工作簿和工作表链接,到最详细的单元格数据校验,都可以通过JSAPI来支持。目前看来,ExcelJSAPI并没有设置能力边界,它会在Excel的整个生命周期中不断完善和开放所有可编程的地方。首先是工作簿和工作表的操作,以及用户对工作表的操作的监控,或者工作表的只读设置。此类API的目的是以编程方式操作整个Excel。第二步是单元格层面的操作,比如选择单元格区域,获取选中区域,或者设置单元格属性和颜色,或者校验单元格数据。自定义公式也在这个链接里,因为单元格的值可以是公式,可以使用JSAPI扩展公式。最后一步是扩展行为,即在单元格的基础上引入图表和数据透视表扩展。虽然这些功能也可以在UI按钮上操作,但是JSAPI可以实现在UI界面上无法配置的逻辑。对于非常复杂的逻辑行为,即使可以配置UI,可读性也远不及代码。除了表格数据透视表,您还可以创建一些自定义形状,支持基本几何形状、图片和SVG。JSAPI设计的有趣之处在于Excel没有抽象的“单元格”对象,尽管我们所有人都认为单元格就是Excel所代表的。这样做是出于API设计的原因,因为Excel使用范围概念来表示连续的单元格。例如:Excel.run(function(context){varsheet=context.workbook.worksheets.getActiveWorksheet();varheaders=[["Product","Quantity","UnitPrice","Totals"]];varheaderRange=sheet.getRange("B2:E2");headerRange.values=headers;headerRange.format.fill.color="#4472C4";headerRange.format.font.color="white";returncontext.sync();});可以发现Range让Excel专注于批处理单元格API,即将单元格看成一个范围,可以围绕一个范围来设计整体的API。这种设计理念的好处是可以通过将范围限制在单个单元格来覆盖Cell的概念,在关注多个单元格时,非常方便基于二维创建表格、折线图等分析图形数据结构。因为具有二维结构的数据是结构化数据。或者可以说结构化数据是Excel的核心概念,单元格不能体现结构。结构化数据的优点是工作表是可以用于分析的数据集。无论是基于单元格的条件格式化还是创建分析图表,都是一种二次数据分析行为。所有这些都受益于结构化数据,因此ExcelJSAPI必须围绕结构化数据进行抽象。从API语法上看,除了工作簿级别的API使用Excel.createWorkbook();外,其他大部分API都是如下形式:Excel.run(function(context){//varsheet=context.workbook.worksheets.getItem("Sample");//操作工作表..returncontext.sync();});最外层的函数Excel.run是用来注入上下文的,它也可以保证Excel执行上下文就绪。而context.sync()是同步操作,即使当前对context的操作生效。所以ExcelJSAPI是命令式的,不会做类似MVVM的双向绑定,所以数据和Excel状态在运行过程中不会发生变化,直到context.sync()被执行。注意到这一点后,你就能理解为什么有些代码要写在context.sync().then中,例如:Excel.run(function(ctx){varpivotTable=context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("FarmSales");//从布局中获取每个数据层次结构的总计。varrange=pivotTable.layout.getDataBodyRange();vargrandTotalRange=range.getLastRow();grandTotalRange.load("address");returncontext.sync().then(function(){//对PivotTable数据层次结构中的总数求和,并将它们放在PivotTable之外的新范围内。varmasterTotalRange=context.workbook.worksheets.getActiveWorksheet().getRange("E30");masterTotalRange.formulas=[["=SUM("+grandTotalRange.address+")"]];});}).catch(errorHandlerFunction);这是从数据透视表中获取数据的示例,grandTotalRange.address只能在执行context.sync()后获取。综上所述,微软在办公套件Excel、Outlook、Word中也推出了ScriptLab功能,你可以在Excel的ScriptLab中编写ExcelJSAPI。在ExcelJSAPI之上,还有一个通用API,定义为跨应用的通用API,这样ExcelJSAPI就可以专注于Excel产品本身的能力。讨论地址为:Jingdu《Excel JS API》·Issue#387·dt-fe/weekly想参与讨论的请戳这里,每周都有新话题,周末或周一发布。前端精读——帮你过滤靠谱的内容。关注前端精读微信公众号
