使用 Javascript 根据 HTML table 的选定行动态计算每一列的总数
Dynamically calculating total for each column based on selected rows for HTML table using Javascript
根据图片,我正在尝试计算所选行 a 和 c 的每列的总数。如果我从函数 calculateCols 中解包代码,该代码就可以工作。是否可以使其在包装函数中工作。我希望能够选择行的变体来对每一列求和,而无需复制和粘贴代码并为每一列编辑多次。
function calculateCols(ID, calculate) {
var final = 0
var tbody = document.querySelector('tbody');
var howManyCols = tbody.rows[0].cells.length;
var totalRow = document.getElementById(ID);
for (var j = 1; j < howManyCols; j++) {
final = calculate;
const check = document.createElement('td');
check.innerText = final;
totalRow.appendChild(check);
}
function getRow(rowID) {
var result = 0;
try {
var check = document.getElementById(rowID)
var thisNumber = parseInt(check.cells[j].childNodes.item(0).data);
if (!isNaN(thisNumber))
result += thisNumber;
} finally {
return result;
}
}
}
calculateCols('total', getRow('a') + getRow('c'));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tbody>
<tr>
<td></td>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td>
<td>6</td>
<td>8</td>
<td>5</td>
</tr>
<tr id="total">
<th scope="row" id="Total">Total a + c</th>
</tr>
</tbody>
</table>
<script src="checkit.js"></script>
</body>
</html>
应该这样做:
function rpn(inps, D, i) { // Reverse Polish Notation calculator
const st = [];
inps.split(/\s+/).forEach(t => {
let k = st.length - 2; // index of penultimate element on stack
if (!isNaN(t)) st.push(+t);
else switch (t) {
case "+": st[k] += st.pop(); break;
case "-": st[k] -= st.pop(); break;
case "*": st[k] *= st.pop(); break;
case "/": st[k] /= st.pop(); break;
case "**": st[k] = st[k] ** st.pop(); break;
default: st.push(+D[t][i]) // treat current value t as a "variable name" --> D[t][i]
}
});
return st.pop()
}
// sample use (Pythagoras's theorem): rpn("3 2 ** 4 2 ** + .5 **") // = 5
// get all table data into D first:
const D = [...document.querySelectorAll("tr[id]")].reduce((da, tr) => {
da[tr.id] = [...tr.children].slice(1).map(td => +td.textContent);
return da;
}, {});
document.querySelectorAll("tr[data-eqn]").forEach(tr =>
[...tr.children].slice(1).forEach((td,k)=>
td.textContent=rpn(tr.dataset.eqn, D, k).toFixed(4).replace(/\.?0*$/,"")));
td,th {text-align: right; padding:4px}
td {border:1px solid grey}
table {border-collapse:collapse}
<table id="tbl">
<tbody>
<tr>
<th></th>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td><td>2</td><td>3</td><td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td><td>6</td><td>4</td><td>5</td>
</tr>
<tr data-eqn="a 2 ** b 2 ** + .5 **">
<th scope="row">sqrt(a²+b²)</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td><td>5</td><td>6</td><td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td><td>6</td><td>8</td><td>5</td>
</tr>
<tr data-eqn="2 a * d + c -">
<th scope="row">2a + d - c</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="a b - a b + / c *">
<th scope="row">(a - b) / (a + b) * c</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="b c /">
<th scope="row">b/c</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="a b +">
<th scope="row">a + b</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="c b +">
<th scope="row">c + b</th>
<td></td><td></td><td></td><td></td>
</tr>
</tbody>
</table>
我再次完全改变了我的答案:操作的中心部分现在是一个 RPN 计算器(函数 rpn()
),它遍历所有如此确定的结果中由 data-eqn
属性提供的指令字符串- <tr>
s.
在开始计算之前,我将所有提供的 table 数据收集到一个全局对象 D
中。所有具有 id
属性的 tr
将它们的 td.textContent
贡献给一个向量,该向量变为 属性 D[id]
。 D
最终成为数组对象。
[[ 目前结果限制为 3 位数。这可以通过再次删除 .toFixed(3)
轻松关闭。 ]]
您调整了范围(帮助:https://davidwalsh.name/for-and-against-let)。
例如check.cells[j]
总是returnhowManyCols-1
.
第一个错误(调试器也警告),getRow
函数在calculateCols
函数内,但调用(calculateCols('total',getRow('a'),getRow('c'))
)不在
我写了一个更简单的代码。
let results = {a: 0, b: 0, c: 0, d: 0};
rows = ['a', 'b', 'c', 'd'];
for (let i = 0; i < rows.length; i++) {
document.querySelectorAll('#'+rows[i]+' td').forEach(
function(elem) {
results[rows[i]] += Number(elem.textContent)
}
)
}
for (let i=0;i<rows.length;i++) {
let result = document.createElement('td');
result.textContent = results[rows[i]];
document.querySelector('#total').appendChild(result);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tbody>
<tr>
<td></td>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td>
<td>6</td>
<td>8</td>
<td>5</td>
</tr>
<tr id="total">
<th scope="row" id="Total">Total</th>
</tr>
</tbody>
</table>
<script src="checkit.js"></script>
</body>
</html>
如果您只想获取 a
和 c
行的数量,请设置列表 rows
['a','c']
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tbody>
<tr>
<td></td>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td>
<td>6</td>
<td>8</td>
<td>5</td>
</tr>
<tr id="total">
<th scope="row" id="Total"></th>
</tr>
</tbody>
</table>
<script>
function toIntOrZero(value) {
let toInt = parseInt(value);
return !isNaN(toInt) ? toInt : 0;
}
function getRowValues(rowID) {
let children = document.getElementById(rowID).children;
let values = [];
for (let i = 1; i < children.length; i++) {
values.push(toIntOrZero(children[i].innerText));
}
return values;
}
function getRows(rowIds) {
return rowIds.map(id => getRowValues(id));
}
function calculateColSums(array) {
return array.reduce(function (r, a) {
a.forEach(function (b, i) {
r[i] = (r[i] || 0) + b;
});
return r;
}, []);
}
function appendResults(results, rowIds) {
document.getElementById('Total').innerHTML = 'Total of ' + rowIds.join();
var tableTotalRow = document.querySelector('tbody > #total');
var totalColumns = document.querySelector('tbody').rows[0].cells.length;
for (var j = 1; j < totalColumns; j++) {
const colSum = document.createElement('td');
colSum.innerText = results[j - 1];
tableTotalRow.appendChild(colSum);
}
}
function calculateSumOfSelectedRows(rowIds) {
appendResults(calculateColSums(getRows(rowIds)), rowIds);
}
calculateSumOfSelectedRows(['b', 'd']);
</script>
</body>
</html>
根据图片,我正在尝试计算所选行 a 和 c 的每列的总数。如果我从函数 calculateCols 中解包代码,该代码就可以工作。是否可以使其在包装函数中工作。我希望能够选择行的变体来对每一列求和,而无需复制和粘贴代码并为每一列编辑多次。
function calculateCols(ID, calculate) {
var final = 0
var tbody = document.querySelector('tbody');
var howManyCols = tbody.rows[0].cells.length;
var totalRow = document.getElementById(ID);
for (var j = 1; j < howManyCols; j++) {
final = calculate;
const check = document.createElement('td');
check.innerText = final;
totalRow.appendChild(check);
}
function getRow(rowID) {
var result = 0;
try {
var check = document.getElementById(rowID)
var thisNumber = parseInt(check.cells[j].childNodes.item(0).data);
if (!isNaN(thisNumber))
result += thisNumber;
} finally {
return result;
}
}
}
calculateCols('total', getRow('a') + getRow('c'));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tbody>
<tr>
<td></td>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td>
<td>6</td>
<td>8</td>
<td>5</td>
</tr>
<tr id="total">
<th scope="row" id="Total">Total a + c</th>
</tr>
</tbody>
</table>
<script src="checkit.js"></script>
</body>
</html>
应该这样做:
function rpn(inps, D, i) { // Reverse Polish Notation calculator
const st = [];
inps.split(/\s+/).forEach(t => {
let k = st.length - 2; // index of penultimate element on stack
if (!isNaN(t)) st.push(+t);
else switch (t) {
case "+": st[k] += st.pop(); break;
case "-": st[k] -= st.pop(); break;
case "*": st[k] *= st.pop(); break;
case "/": st[k] /= st.pop(); break;
case "**": st[k] = st[k] ** st.pop(); break;
default: st.push(+D[t][i]) // treat current value t as a "variable name" --> D[t][i]
}
});
return st.pop()
}
// sample use (Pythagoras's theorem): rpn("3 2 ** 4 2 ** + .5 **") // = 5
// get all table data into D first:
const D = [...document.querySelectorAll("tr[id]")].reduce((da, tr) => {
da[tr.id] = [...tr.children].slice(1).map(td => +td.textContent);
return da;
}, {});
document.querySelectorAll("tr[data-eqn]").forEach(tr =>
[...tr.children].slice(1).forEach((td,k)=>
td.textContent=rpn(tr.dataset.eqn, D, k).toFixed(4).replace(/\.?0*$/,"")));
td,th {text-align: right; padding:4px}
td {border:1px solid grey}
table {border-collapse:collapse}
<table id="tbl">
<tbody>
<tr>
<th></th>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td><td>2</td><td>3</td><td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td><td>6</td><td>4</td><td>5</td>
</tr>
<tr data-eqn="a 2 ** b 2 ** + .5 **">
<th scope="row">sqrt(a²+b²)</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td><td>5</td><td>6</td><td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td><td>6</td><td>8</td><td>5</td>
</tr>
<tr data-eqn="2 a * d + c -">
<th scope="row">2a + d - c</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="a b - a b + / c *">
<th scope="row">(a - b) / (a + b) * c</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="b c /">
<th scope="row">b/c</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="a b +">
<th scope="row">a + b</th>
<td></td><td></td><td></td><td></td>
</tr>
<tr data-eqn="c b +">
<th scope="row">c + b</th>
<td></td><td></td><td></td><td></td>
</tr>
</tbody>
</table>
我再次完全改变了我的答案:操作的中心部分现在是一个 RPN 计算器(函数 rpn()
),它遍历所有如此确定的结果中由 data-eqn
属性提供的指令字符串- <tr>
s.
在开始计算之前,我将所有提供的 table 数据收集到一个全局对象 D
中。所有具有 id
属性的 tr
将它们的 td.textContent
贡献给一个向量,该向量变为 属性 D[id]
。 D
最终成为数组对象。
[[ 目前结果限制为 3 位数。这可以通过再次删除 .toFixed(3)
轻松关闭。 ]]
您调整了范围(帮助:https://davidwalsh.name/for-and-against-let)。
例如check.cells[j]
总是returnhowManyCols-1
.
第一个错误(调试器也警告),getRow
函数在calculateCols
函数内,但调用(calculateCols('total',getRow('a'),getRow('c'))
)不在
我写了一个更简单的代码。
let results = {a: 0, b: 0, c: 0, d: 0};
rows = ['a', 'b', 'c', 'd'];
for (let i = 0; i < rows.length; i++) {
document.querySelectorAll('#'+rows[i]+' td').forEach(
function(elem) {
results[rows[i]] += Number(elem.textContent)
}
)
}
for (let i=0;i<rows.length;i++) {
let result = document.createElement('td');
result.textContent = results[rows[i]];
document.querySelector('#total').appendChild(result);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tbody>
<tr>
<td></td>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td>
<td>6</td>
<td>8</td>
<td>5</td>
</tr>
<tr id="total">
<th scope="row" id="Total">Total</th>
</tr>
</tbody>
</table>
<script src="checkit.js"></script>
</body>
</html>
如果您只想获取 a
和 c
行的数量,请设置列表 rows
['a','c']
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<tbody>
<tr>
<td></td>
<th scope="col">2013</th>
<th scope="col">2014</th>
<th scope="col">2015</th>
<th scope="col">2016</th>
</tr>
<tr id="a">
<th scope="row">a</th>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr id="b">
<th scope="row">b</th>
<td>5</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr id="c">
<th scope="row">c</th>
<td>4</td>
<td>5</td>
<td>6</td>
<td>7</td>
</tr>
<tr id="d">
<th scope="row">d</th>
<td>5</td>
<td>6</td>
<td>8</td>
<td>5</td>
</tr>
<tr id="total">
<th scope="row" id="Total"></th>
</tr>
</tbody>
</table>
<script>
function toIntOrZero(value) {
let toInt = parseInt(value);
return !isNaN(toInt) ? toInt : 0;
}
function getRowValues(rowID) {
let children = document.getElementById(rowID).children;
let values = [];
for (let i = 1; i < children.length; i++) {
values.push(toIntOrZero(children[i].innerText));
}
return values;
}
function getRows(rowIds) {
return rowIds.map(id => getRowValues(id));
}
function calculateColSums(array) {
return array.reduce(function (r, a) {
a.forEach(function (b, i) {
r[i] = (r[i] || 0) + b;
});
return r;
}, []);
}
function appendResults(results, rowIds) {
document.getElementById('Total').innerHTML = 'Total of ' + rowIds.join();
var tableTotalRow = document.querySelector('tbody > #total');
var totalColumns = document.querySelector('tbody').rows[0].cells.length;
for (var j = 1; j < totalColumns; j++) {
const colSum = document.createElement('td');
colSum.innerText = results[j - 1];
tableTotalRow.appendChild(colSum);
}
}
function calculateSumOfSelectedRows(rowIds) {
appendResults(calculateColSums(getRows(rowIds)), rowIds);
}
calculateSumOfSelectedRows(['b', 'd']);
</script>
</body>
</html>