本帖最后由 Wilson.Zhang 于 2024-11-30 20:52 编辑
背景:在单元格输入自定义函数如何显示其描述信息,以及如何将自定义函数添加至“插入函数”列表。
问题原帖:
https://gcdn.grapecity.com.cn/forum.php?mod=viewthread&tid=229411
https://gcdn.grapecity.com.cn/forum.php?mod=viewthread&tid=229525
如图1所示,公式函数的描述信息被保存在Function对象的description公式中,即在单元格输入公式时,SpreadJS的计算引擎会调用公式函数对应Function对象的description获取其描述信息和参数信息予以提示,向用户介绍公式的作用以及使用方式。因此,在自定义函数时,重写其prototype的description方法,按照接口规定封装公式函数描述信息和参数信息,并将其通过方法返回即可。
图1. Function:description()
在工具栏“公式-->插入函数”列表中可以查找并选择SpreadJS内置支持的所有计算公式,然而,默认情况下不会自动将自定义函数添加至此。“插入函数”列表是一个对话框,在SpreadJS中,这类用以显示提示信息而存在的对话框均以Template存在,SpreadJS管理着这些Template。如果需要在某个Template添加或删除内容,甚至需要改写或替换某个Template,都需要将新Template注册在对应的Template名称上。针对当前场景,需要先从SpreadJS获取“插入函数”对应的Template,如图2所示,Template中显示的内容均保存在content属性中。
图2. “插入函数”Template对象数据结构
继续分析content属性值的数据结构,如图3所示,可以看到“插入函数”对话框中分列于左右两侧的“函数类别”和“选择函数”分别以Array数据类型存在于content[0].children[0].children数组。具体地,content[0].children[0].children[0]存储了“函数类别”及其包含的所有函数类别的名称,而content[0].children[0].children[1]存储了每个函数类别包含的函数名称列表。
图3. content数据结构
相应地,自定义函数的名称也应该被保存在content[0].children[0].children[1]属性值中。在content[0].children[0].children[1].children[1]属性值也是Array数组,数组内保存了13个对象,每个对象对应为一种函数类别的函数列表。如图4所示,每个函数列表对应的对象的bindingPath属性值映射了这组函数与左侧某个函数类别的关系,items属性值即是这组函数的名称列表。那么,只需要按照数据结构将自定义函数的名称添加在某个函数类别对应的函数列表数组中即可。
图4. 分组函数列表数据结构
在以上分析Template对象数据结构的过程中,可以了解到其对象结构天生具有递归性,那么,可以合理利用这层性质组织高可用的代码进行递归操作。当然也可以直接使用上述分析的结果,直接明了地通过对象属性简洁地赋值。
本文实践实现了上述方式,如图5所示,可以看到在单元格中输入自定义函数名称FACTORIAL的过程中伴有弹窗显式公式函数的介绍信息,而且,“插入函数”列表的“全部”和“数据库”两个类别中分别保存了FACTORIAL。
图5. 自定义函数加入内置函数列表
附上demo抛砖引用,以供参考了解。需要提醒一点,目前对于在“插入函数”列表的“函数类别”中自定义类别后添加函数的支持较弱,不过产品计划增强这项功能支持,可能在后续版本中可见,届时本文也会同步更新。
|