目前luckysheet存在的问题
问题1
现有A、B两个sheet页,A页有个公式,公式表达式是将B页中的两个单元格相加。如图-1.
图-1
将A页的B列删除,发现公式竟然也跟着发生了变化,如图-2
正确的效果应该是公式不会改变,还是"B!I5+B!J5"
问题2
继续问题1的操作,来到B页,将B页的C列删除,回到A页,公式引用却没有改变。在excel中是会改变的。
所以,luckysheet中对于跨sheet的公式引用更新是不准的。
原因
查阅源码发现,luckysheet在处理时,只会更新本页面的公式,并且会将公式中其他sheet页的参数也跟着更新。所以需要解决跨sheet页的公式胡乱更新的问题。
解决
更新原则:在“操作页”删除一列后,“操作页”中除本页外的所有公式的参数都不应该改变,除“操作页”以外的其他sheet页的公式只更新含“操作页”单元格的参数。
代码
(extend.js)在原有的公式更新之前,完成对其他sheet的公式更新,主要更新和“操作页”有关的参数。
更新的核心是formula.functionStrChange方法,还需要对这个方法进行改造。
(formula.js)写个函数getFuncStr负责判断参数是否需要更新,如下:
然后在functionStrChange中调用上面写的函数。
代码
extend.js
// nby 多页面的公式引用
// 先更新其他页面的公式
Store.luckysheetfile = luckysheet.getAllSheets() //这里需要更新Store.luckysheetfile
let otherSheet = Store.luckysheetfile.filter((it)=>it.index !== file.index && it.calcChain?.length > 0)
otherSheet?.forEach((sheetFile,sheetIndex)=>{
let opeArr = sheetFile.celldata?.filter(cell=>sheetFile.calcChain?.findIndex(calc=>calc.r===cell.r&&calc.c===cell.c)!=-1 )
opeArr.forEach((cell,cellIndex)=>{
if(cell.v?.f.includes(file.name)){
let calc_r = cell.r
let calc_c = cell.c
let calc_funcStr = cell.v.f
let functionStr = ''
if(type == "row"){
// if(calc_r < st || calc_r > ed){
functionStr = "=" + formula.functionStrChange(calc_funcStr, "del", "row", null, st, slen,true);
// }
}
else if(type == "column"){
functionStr = "=" + formula.functionStrChange(calc_funcStr, "del", "col", null, st, slen,true);
}
// 更新公式
let curCelldata = Store.luckysheetfile[sheetFile.order].celldata.find(ce=>ce.c==cell.c&&ce.r==cell.r)
curCelldata.v.f = functionStr
Store.luckysheetfile[sheetFile.order].data = []
}
})
})
// nby 多页面的公式引用 END
formula.js
getFuncStr(str, rightStr,result){
let function_str = ''
let sheetStr = str.split('!')[0]
let sheetFile = Store.luckysheetfile.find((it)=>it.name==sheetStr)
if(sheetFile){
if(sheetFile.index != Store.currentSheetIndex){
function_str += str + rightStr; //参数不更新
}else{
function_str += result + rightStr;
}
}else{
function_str += result + rightStr
}
return function_str
},
getFuncStr调用
在functionStrChange中需要的位置进行调用
// ...
else if (s == ',' && matchConfig.dquote == 0) {
// 源码如下:
// function_str += _this.functionStrChange(str, type, rc, orient, stindex, step) + ',';
// str = "";
// nby 多页面的公式引用
function_str += _this.getFuncStr(str,',',_this.functionStrChange(str, type, rc, orient, stindex, step))
str = "";
// nby 多页面的公式引用 END
}
// ...
思考
实现的原理还是筛选数组后再循环更新,想着能不能用响应式来实现,看了看整体代码发现不好做。不知道excel中是如何做的?