最近一个同学反馈,导入了一个带有公式的excel表以后,公式有部分不能生效,因为我们之前发现导入的Excel后,确实有这样子的问题,所以首先需要确认的是本身在luckysheet上做的公式是否是支持的。结果确认后发现本身也不行,所以问题已经确定是在luckysheet上,而不是excel导入的问题了。
分析
我们先来简化的看下,到底是什么样的公式是存在问题的,这里面其实涉及到的矩阵的转置。
首先我们看上图,上图的逻辑就是把横向的矩阵数据转置成了纵向,所以一旦源矩阵的数据如果发生变化的话,对应转置举证的数据也会发生变化。
下来我们增加新的引用关系, 如下图:
在某个单元格中去引用转置后的举证的其中一个单元格, 所以理论上我们希望会得到这样子的一个结果,就是一旦我修改了原单元格中的矩阵数据,相应转置的矩阵数据也会发生变化,同时引用了转置举证的单元格数据也要随着去更新。但是实际的结果是并没有。我们看下最后的结果现象
从上图就可以看出来更新了原矩阵的值后,下方选中的单元格数据并没有发生变化。遇到这样子的情况我们首先需要先确认一个事情即这个问题是因为举证转置导致的 还是本身引用的引用导致的这个问题。
所以我们重新做一个验证,如下图:
有如上的三者之前的关系,验证发现,通过修改原数据以后,选中的单元格数据其实是会发生更新的,所以我们大体可以确认一个问题即这个问题可能更多是跟矩阵转置有关系。
那现在我们就要排查下,问题出在哪个地方了。
首先我们得找到入口的地方,看了下代码逻辑后,终于发现了,在更新某个单元格后,如果该单元格只是纯文本的更新 没有其他公式引用的话,就会调用到 execFunctionGroup
方法。
所以我们需要看下 execFunctionGroup
他的具体逻辑是如何的。
这块的逻辑其实比较复杂 我们找到其中重点一个地方来看下
//形成一个公式之间引用的图结构
Object.keys(formulaObjects).forEach((key) => {
let formulaObject = formulaObjects[key];
arrayMatch(formulaObject.formulaArray, formulaObjects, updateValueOjects, function (childKey) {
if (childKey in formulaObjects) {
let childFormulaObject = formulaObjects[childKey];
formulaObject.chidren[childKey] = 1;
childFormulaObject.parents[key] = 1;
}
// console.log(childKey,formulaObject.formulaArray);
if (!isForce && childKey in updateValueOjects) {
updateValueArray.push(formulaObject);
}
});
if (isForce) {
updateValueArray.push(formulaObject);
}
});
从这个地方的调试发现,经过公式引用图那块的逻辑处理后,我们的 I4
那块的方法就被过滤掉了。所以问题很大概率就出现在那块了。我们详细看下这块的逻辑吧。
我们发现那块的逻辑又调用到了 arrayMatch
这个方法。
let arrayMatch = function (formulaArray, formulaObjects, updateValueOjects, func) {
for (let a = 0; a < formulaArray.length; a++) {
let range = formulaArray[a];
let cacheKey = "r" + range.row[0] + "" + range.row[1] + "c" + range.column[0] + "" + range.column[1] + "index" + range.sheetIndex;
if (cacheKey in arrayMatchCache) {
let amc = arrayMatchCache[cacheKey];
// console.log(amc);
amc.forEach((item) => {
func(item.key, item.r