惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fortinet All Blogs
V
Visual Studio Blog
T
Tor Project blog
量子位
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
有赞技术团队
有赞技术团队
博客园 - 司徒正美
博客园_首页
罗磊的独立博客
美团技术团队
人人都是产品经理
人人都是产品经理
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
C
Check Point Blog
博客园 - 聂微东
爱范儿
爱范儿
Schneier on Security
Schneier on Security
T
Threat Research - Cisco Blogs
T
Tailwind CSS Blog
L
LINUX DO - 热门话题
大猫的无限游戏
大猫的无限游戏
V
Vulnerabilities – Threatpost
C
Cisco Blogs
GbyAI
GbyAI
Spread Privacy
Spread Privacy
博客园 - 叶小钗
博客园 - 【当耐特】
T
Tenable Blog
雷峰网
雷峰网
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
J
Java Code Geeks
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
Microsoft Azure Blog
Microsoft Azure Blog
Simon Willison's Weblog
Simon Willison's Weblog
N
Netflix TechBlog - Medium
T
The Exploit Database - CXSecurity.com
腾讯CDC
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
阮一峰的网络日志
阮一峰的网络日志
Scott Helme
Scott Helme
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Martin Fowler
Martin Fowler

博客园 - lichdr

高德地图热力图的Flutter实现 App消息推送的简单实现 nginx访问日志过滤(多条件) CAS的service参数验证 自定义Token的CAS登录 表格行列的删除 表格行列的移动 FastReport的一些另类用法 FastReport分组页码 RFID会议签到系统总结(二十二)――系统中的模式 RFID会议签到系统总结(二十一)――服务端的通讯 RFID会议签到系统总结(二十)――数据窗体状态控制 RFID会议签到系统总结(十九)――单数据窗体 RFID会议签到系统总结(十八)――菜单与工具栏的加载 RFID会议签到系统总结(十七)――菜单与工具栏的改造(下) RFID会议签到系统总结(十六)――菜单与工具栏按钮的改造(上) RFID会议签到系统总结(十五)――管控端的窗体组织 RFID会议签到系统总结(十四)――管控端业务模块的加载 RFID会议签到系统总结(十三)――模块概述(下)
单元格的计算
lichdr · 2010-11-19 · via 博客园 - lichdr

  在如Excel一样的表格中,某些单元格是靠计算产生值的,不用人工填写。本来使用的是Farpoint Spread 这个控件,生成表头,设定了公式,锁定列等等看来都很好使,界面也很好。

  静态计算是没什么问题的,即页面第一次加载生成时计算那些单元格的值;但是动态计算上体验不太完美,利用它自己内置的功能反应不够灵敏,公式涉及的行列越多,计算层次越深其反应越不灵敏。鉴于我们遇到的公式基本只有二种,合计与百分比,遂自己写脚本来动态更新相关单元格的值。

  设定事件,取得行列索引不细表,直接进入正题

计算单元格

function calcValue(sheet, currentRow, currentCol, level) {
var sumFormulaExp = /R(\d+)C(\d+)\+/g; //相加的表达式
var percentFormulaExp = /IF\(R(\d+)C(\d+)=0,\S{3},R(\d+)C(\d+)\*100\/R(\d+)C(\d+)\)/g; //计算百分比的表达式

var formulaPart = "R" + currentRow + "C" + currentCol; //exp:R4C3
$("td[fpformula*='" + formulaPart + "']").each(function() { //exp:找公式中包含有R4C3的单元格
//。。。计算相关单元格的值
});
}

四个参数:  sheet--当前sheet,从页面上能取到的那个控件对象

      currentRow--当前行号,从1开始计数

      currentCol--当前列号,从1开始计数

      level--层次,递归调用时控制层次

特别说明一下那个level参数,这是以防万一公式设定错误导致无休止调用发生错误而设的。为什么会发会递归调用,因为一个值发生改变后会涉及到多个多行多列单元格的值发生联动。比如R7C7的单元格(即7行7列)数字变动了,那它的行小计R7C4、行合计R7C1、列小计R4C7、列合计R1C7,以及最终的总计R1C1都要发生变动,上述单元格有参与百分比计算的也要重新计算相关的百分比。输入值的单元格=》行小计=》行合计=》总计的这个过程就是递归调用过程,递归的终点是在当前表格中找不到有任何一个单元格公式表达式中包含有当前单元格。这个传递过程只有那个累加的单元格才会发生传递,计算百分比的单元格是不会往下传递的,比如一个行合计相关的百分比单元格R9C1(=R8C1/R7C1),这个R9C1是不用往下传递到合计百分比单元格R3C1(=R2C1/R1C1)的。

  当前单元格有没有被计算是字符串包含来匹配的。还是以R7C7来举列,跟它有关的公式会找到二个,

R7C4上的累加公式:R7C7+R7C8+R7C9+R7C10+

R9C7上的百分比公式:IF(R7C7=0,'-',R8C7/R7C7) 

接下来就是计算R7C4,R9C7时里的新值。

计算之前先作一个预处理,R7C7的话还一般不会有干扰。但如果是找R7C1,你找到了一个公式R7C10 + R7C11,jquery选择里会把这个公式与列为有效公式,计算是不会出错,但效率会差很多。所以用一个正则把干扰公式排除掉

排除匹配不准确的单元格

var cellExp = new RegExp(formulaPart + "\\D{1}", "");
var formula = $(this).attr("fpformula");
if (!cellExp.test(formula))//jquery的选择器匹配出来的是弱的,用正则强匹配一下。
return;

接下来要用正则表达式去匹配公式了

公式匹配

var mat = sumFormulaExp.exec(formula);
var percentMat = percentFormulaExp.exec(formula);var colIndex = parseInt($(this).parent().children().index($(this))) + 1;
var rowIndex = parseInt($(this).parent().attr("fpkey")) + 1;if (mat != null) {
//...计算合计
} else if (percentMat != null) {
//。。。计算百分比
}

累加的处理

var result = 0;
while (mat != null) {
var row = parseInt(mat[1]) - 1;
var col = parseInt(mat[2]) - 1;
var v = parseFloat(sheet.GetValue(row, col));
result
+= v;
mat
= sumFormulaExp.exec(formula);
}
$(
this).children("nobr").text(result);if (level < 4) {//5层已经够用了
var dl = parseInt(level) + 1;
calcValue(sheet, rowIndex, colIndex, dl);
}

百分比的处理

var mRow, mCol, cRow, cCol;
mRow
= parseInt(percentMat[1]) - 1;
mCol
= parseInt(percentMat[2]) - 1;
cRow
= parseInt(percentMat[3]) - 1;
cCol
= parseInt(percentMat[4]) - 1;
percentFormulaExp.lastIndex
= 0;var denominator = parseFloat(sheet.GetValue(mRow, mCol));
if (denominator == 0)
$(
this).children("nobr").text("-");
else {
var numerator = parseFloat(sheet.GetValue(cRow, cCol));
var percent = numerator * 100 / denominator;
percent
= percent.toFixed(1);
$(
this).children("nobr").text(percent);
}

上面sheet.GetValue()是控件提供的方法,用来取单元格的值。fpformula是设定的公式,根据数据库里的定义,在第一次加载时在服务端就都设定好了,公式格式是控件支持的,所以静态计算也支持的,首次显示时相关单元格会自动计算。那个$(this).children("nobr").text里的nobr纯粹是查看控件生成的html代码得到的。

  经过上述一些处理,现在页面上相应格子里输入一个值一回车,跟它有关的七、八个单元格的值立马就发生了变化,跟在本地编辑Excel文件一样的速度。不过万恶的IE愣是要慢半拍,如果表格超过10行或10列的话更明显,至少要多1秒。以后可以拿这个功能去说服那些人远离IE。