js动态表格计算问题
现在有一个动态表格,用户可以随意增加删除行(这个功能已经实现),现在的问题是:当这些行都在变化时,如何计算出合计呢?
以下是动态表格程序:
<script type="text/javascript">
var $cc = function(id){
return document.getElementById(id);
}
//全选
function checkAll(target){
var checkeds = document.getElementsByName("b_id");
for (var i =0;i<checkeds.length;i++) {
checkeds[i].checked=target.checked;
}
}
//刷新行号
function refreshRowNo(){
var tbody = $cc("tbody");
for (var i =0;i<tbody.rows.length;i++){
tbody.rows[i].cells[0].innerHTML=i+1;
}
var xxx=tbody.rows.length;
document.getElementById('xh').value=xxx;
}
//添加行
function AddRow() {
var tbody = $cc("tbody");
var row = tbody.insertRow(tbody.rows.length);
var sss=tbody.rows.length;
row.insertCell(row.cells.length);
row.insertCell(row.cells.length).innerHTML = '<input type="checkbox" name="b_id" style="max-width:20px;max-height:20px;"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpmc'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpgg'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpcz'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpdw'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpsl'+sss+']" style="width:120px" class="num"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpbiaozhun'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpbeizhu'+sss+']" style="width:120px"/>';
refreshRowNo();
}
//删除行
function DelRow() {
var checkeds = document.getElementsByName("b_id");
var ischeck = false;
for (var i = checkeds.length - 1; i >= 0; i--) {
if (checkeds[i].checked) {
ischeck = true;
break;
}
}
if (ischeck) {
if (confirm("确定删除选中行?")) {
for (var i = checkeds.length - 1; i >= 0; i--) {
if (checkeds[i].checked) {
var index = checkeds[i].parentNode.parentNode.rowIndex;
$cc("tbody").deleteRow(index - 1);
}
}
refreshRowNo();
}
}else{
alert("请选中需要删除的行!");
}
}
</script>
<div class="second1-right">
<table cellpadding="1" cellspacing="2" style="border-collapse:collapse">
<tr>
<th style="width:40px">序号</th>
<th style="width:max-width:20px;max-height:20px;"><input type="checkbox" onclick="checkAll(this)" /></th>
<th style="width:240px">产品名称</th>
<th style="width:240px">规格</th>
<th style="width:120px">材质</th>
<th style="width:120px">单位</th>
<th style="width:120px">数量(台)</th>
<th style="width:120px">标准</th>
<th style="width:120px">备注</th>
</tr>
<tbody id="tbody">
<tr>
<input id="xh"type="hidden" name="hlqgcp[xuhao]" value="1" >
<td style="width:40px">1</td>
<td><input type="checkbox" name="b_id" style="max-width:20px;max-height:20px;"/></td>
<td><input type="text" name="hlqgcp[hlqgcpmc1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpgg1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpcz1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpdw1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpsl1]" style="width:120px" class="num"/></td>
<td><input type="text" name="hlqgcp[hlqgcpbiaozhun1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpbeizhu1]" style="width:120px"/></td>
</tr>
</tbody>
<tr>
<td ></td>
<td></td>
<td style="text-align:center; color:#0087CB; ">总计:</td>
<td></td>
<td></td>
<td></td>
<td style="text-align:center; color:#0087CB; border-right:0"></td>
<td></td>
<td ></td>
</tr>
</table>
<ul>
<li>
<input type="button" onclick="AddRow()" value="增加一行" class="second1-right-anniu"/>
<input type="button" onclick="DelRow()" value="删除" class="second1-right-anniu"/>
</li>
</ul>
</div>
Answers
原生,硬派!
不急着写代码,先看需求。“行变化时重新计算总和”这个太浅显了,事实上离需求的本质还有点远。这个需求其实暗含了这样一个三段论的分析:
- 表格的行增删会引发 数据变化 。
- 单元格内输入了合法内容都会引发 数据变化 。
- 在 数据变化 时,需要重复计算并更新总和。
“数据变化”才是这个需求的本质和枢纽。某些事件触发实质数据变化,而无论原因是什么,只要数据变化了就要触发后续的计算动作。
所以这个需求你需要一个 事件模型 。
事实上大多数浏览器都支持 原生的自定义事件系统 ,但偏偏恨人的是IE任何版本都不支持……
所以这时候就该上jQuery,填平浏览器之间实现不一致的坑:
这个实现的关键点在于事件冒泡。
数据变化
事件的实体只在
<table>
上绑定一次,但表格中任意子元素都可以响应
数据变化
事件。这个响应的原理是:子元素无对应事件的行为时,会将事件逐级上报,最终必然在
<table>
上统一处理。
你不是可以取到指定的列吗?根据你第一个图,要求和的列是第七列,数组下标是6。
同时,你不是也可以取到有效的数据行数吗?无论你增加或删除操作,操作结束后的表格都可以映射为一个固定的二维数组,已经可以计算求和了呀,难道是我理解错误。
如果不是准备单独写操作结束后的遍历求和的方法(实际上也没有必要),在你refreshRowNo的方法中已经在做这样的事情了。每当添加完或删除完都会执行刷新行标的动作,这时已经可以取到相应栏位的值,我的思路是将其存入一个全局的数组中,以供后面求和使用。
在复选框选中或取消选中时,删除或保留数组中对应下标的值,最后在对数组的值进行求和,就可以得到你想要的总计数值了吧。
简单的代码是这样:
var cells; //用于存储每行的数量
//刷新行号
function refreshRowNo(){
var tbody = $cc("tbody");
cells = [];
for (var i =0;i<tbody.rows.length;i++){
tbody.rows[i].cells[0].innerHTML=i+1;
cells.push(tbody.rows[i].cells[6].innerHTML);
}
var xxx=tbody.rows.length;
document.getElementById('xh').value=xxx;
}
//为你的checkbox点击事件加入这样的处理,我这里写的是jquery的选择方式,仅仅是想表达出这个思想。
//或者将我的这个思路改成符合你操作逻辑的方法
function checkClick(obj){
//之前存下的cells数组中,index和行号的关系是index = rowNo-1,这个没有错对吧
//所以这里根据行号获取到下标
var index = parseInt($(obj).parent().prev('td').html())-1;
if($(obj).prop("checked")){
//原来没选中,现在选中的情况,需要计算入总计
sum(index);
}else{
//原来选中,现在取消选中的情况,需要从总计中减掉
minus(index);
}
}
function sum(index){
//总计那一行既然是固定的,给目标栏位加上ID应该更好操作些
var sum = parseInt($("#sum").html()==""?"0":$("#sum").html()); //当前的总和,没有则为0
sum += parseInt(cells[index]);
$("#sum").html(sum);
}
function minus(index){
//总计那一行既然是固定的,给目标栏位加上ID应该更好操作些
var sum = parseInt($("#sum").html()==""?"0":$("#sum").html()); //当前的总和,没有则为0
sum -= parseInt(cells[index]);
$("#sum").html(sum);
}
这样一来,每当你添加或者删除行后刷新行号的同时,将所有行的待计算项存入这个空数组中,然后根据checkbox的勾选情况选择相应的值进行计算。
不知道这个答案是否符合题主所述问题?
<script type="text/javascript">
var $cc = function(id){
return document.getElementById(id);
}
//全选
function checkAll(target){
var checkeds = document.getElementsByName("b_id");
for (var i =0;i<checkeds.length;i++) {
checkeds[i].checked=target.checked;
}
}
//刷新行号
function refreshRowNo(){
var tbody = $cc("tbody");
for (var i =0;i<tbody.rows.length;i++){
tbody.rows[i].cells[0].innerHTML=i+1;
}
var xxx=tbody.rows.length;
document.getElementById('xh').value=xxx;
}
//添加行
function AddRow() {
var tbody = $cc("tbody");
var row = tbody.insertRow(tbody.rows.length);
var sss=tbody.rows.length;
row.insertCell(row.cells.length);
row.insertCell(row.cells.length).innerHTML = '<input type="checkbox" name="b_id" style="max-width:20px;max-height:20px;"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpmc'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpgg'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpcz'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpdw'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpsl'+sss+']" style="width:120px" class="num"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpbiaozhun'+sss+']" style="width:120px"/>';
row.insertCell(row.cells.length).innerHTML = '<input type="text" name="hlqgcp[hlqgcpbeizhu'+sss+']" style="width:120px"/>';
refreshRowNo();
}
//删除行
function DelRow() {
var checkeds = document.getElementsByName("b_id");
var ischeck = false;
for (var i = checkeds.length - 1; i >= 0; i--) {
if (checkeds[i].checked) {
ischeck = true;
break;
}
}
if (ischeck) {
if (confirm("确定删除选中行?")) {
for (var i = checkeds.length - 1; i >= 0; i--) {
if (checkeds[i].checked) {
var index = checkeds[i].parentNode.parentNode.rowIndex;
$cc("tbody").deleteRow(index - 1);
}
}
refreshRowNo();
}
}else{
alert("请选中需要删除的行!");
}
}
function CountNum(){
var body = $cc('tbody'), count = 0;
for(var i = body.rows.length; i--;){
//每一行的, 第7个单元格(下标为6), firstChild 为 input 的DOM对象
count += body.rows[i].cells[6].firstChild.value * 1;
}
return count;
}
</script>
<div class="second1-right">
<table cellpadding="1" cellspacing="2" style="border-collapse:collapse">
<tr>
<th style="width:40px">序号</th>
<th style="width:max-width:20px;max-height:20px;"><input type="checkbox" onclick="checkAll(this)" /></th>
<th style="width:240px">产品名称</th>
<th style="width:240px">规格</th>
<th style="width:120px">材质</th>
<th style="width:120px">单位</th>
<th style="width:120px">数量(台)</th>
<th style="width:120px">标准</th>
<th style="width:120px">备注</th>
</tr>
<tbody id="tbody">
<tr>
<input id="xh"type="hidden" name="hlqgcp[xuhao]" value="1" >
<td style="width:40px">1</td>
<td><input type="checkbox" name="b_id" style="max-width:20px;max-height:20px;"/></td>
<td><input type="text" name="hlqgcp[hlqgcpmc1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpgg1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpcz1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpdw1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpsl1]" style="width:120px" class="num"/></td>
<td><input type="text" name="hlqgcp[hlqgcpbiaozhun1]" style="width:120px"/></td>
<td><input type="text" name="hlqgcp[hlqgcpbeizhu1]" style="width:120px"/></td>
</tr>
</tbody>
<tr>
<td ></td>
<td></td>
<td style="text-align:center; color:#0087CB; ">总计:</td>
<td></td>
<td></td>
<td></td>
<td style="text-align:center; color:#0087CB; border-right:0"></td>
<td></td>
<td ></td>
</tr>
</table>
<ul>
<li>
<input type="button" onclick="AddRow()" value="增加一行" class="second1-right-anniu"/>
<input type="button" onclick="DelRow()" value="删除" class="second1-right-anniu"/>
<input type="button" onclick="alert(CountNum())" value="计算总合">
</li>
</ul>
</div>