如何保存折叠子行的状态(JS)
How to save state of collapsed children rows (JS)
我正在尝试为一个项目制作一个可折叠的 table,到目前为止,我做得很好。我只遇到一个我不知道如何处理的问题:实际上我的可折叠行(有子行的行)正在折叠,但是如果我折叠一个子行,然后折叠父行,然后展开父行,则children 也被扩展了。如何保存子项的状态,以便在我们展开父项时它们不会展开?
$(document).ready(function() {
// Define color depending on the M1 cell value //
var rows = document.getElementsByTagName("tbody")
[0].getElementsByTagName("tr");
// loops through each row
for (i = 0; i < rows.length; i++) {
cells = rows[i].getElementsByTagName('td');
if (cells[2].innerHTML == '1')
$(cells).parent().addClass('Titre_1');
if (cells[2].innerHTML == '2')
$(cells).parent().addClass('Titre_2');
if (cells[2].innerHTML == '3')
$(cells).parent().addClass('Titre_3');
if (cells[2].innerHTML == '4')
$(cells).parent().addClass('Titre_4');
if (cells[2].innerHTML == '5')
$(cells).parent().addClass('Titre_5');
if (cells[2].innerHTML == '6')
$(cells).parent().addClass('Titre_6');
if (cells[2].innerHTML == '7')
$(cells).parent().addClass('Titre_7');
if (cells[2].innerHTML == '8')
$(cells).parent().addClass('Titre_8');
if (cells[2].innerHTML == '9')
$(cells).parent().addClass('Titre_9');
}
// Expand/collapse when clicking on first column //
function getChildren($row) {
var children = [], level = $row.attr('data-level');
while($row.next().attr('data-level') > level) {
children.push($row.next());
$row = $row.next();
}
return children;
}
$('.colex').on('click', function() {
var action;
if($(this).parent('.parent').hasClass('collapsed')) {
$(this).parent('.parent').removeClass('collapsed');
$(this).text('-');
action = 'show';
} else {
$(this).parent('.parent').addClass('collapsed');
$(this).text('+');
action = 'hide';
}
var children = getChildren($(this).parent('.parent'));
$.each(children, function() {
if(action == "show") {
$(this).removeClass('collapsed').show();
} else {
$(this).addClass('collapsed').hide();
if($(this).children('.colex').text() == '+') { // Replace possible '+' by a '-' when parent's collapsed //
$(this).children('.colex').text('-');
}
}
});
})
})
body {
font-family: sans-serif;
}
body * {
box-sizing: border-box;
/*color: #59547c;*/
margin: 0;
}
main {
/* max-width: 60rem;*/
margin: 1px auto;
padding: 1rem;
}
h1 {
margin-bottom: 1rem;
}
p {
margin-bottom: 1rem;
}
input.variante[type=checkbox] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input.variante[type=checkbox] {
height: 15px;
width: 15px;
background: #fff;
border: 1px solid #ccc;
}
input.variante[type="checkbox"]:checked
{
background: orange;
&:before {
font-family: FontAwesome;
content: '\f00c';
display: block;
color: grey;
font-size: 15px;
position: absolute;
}
}
table {
empty-cells: show;
}
th {
text-align:center;
border: 1px solid antiquewhite;
}
.parent > .colex {
color: black;
cursor: pointer;
}
.table_header {
background-color:#484e82;
color:#fdfdff;
font-weight: bold;
}
.intro {
font-size: 1.125rem;
}
.Titre_1 {
color: red;
}
.Titre_2 {
color: purple;
}
.Titre_3 {
color: fuchsia;
}
.Titre_4 {
color: green;
}
.Titre_5 {
color: lime;
}
.Titre_6 {
color: navy;
}
.Titre_7 {
color: blue;
}
.Titre_8 {
color: aqua;
}
.Titre_9 {
color: orange;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Devis</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<intro>
<p class="intro">description</p>
</intro>
<main>
<table id="mytable" align=center rules=groups frame=box hborder=0 cellspacing=1 cellpadding=4 vborder=1>
<thead class="table_header">
<th id="colex" width=2%>Co<br/>Ex</th>
<th id="h_M8" width=2%>V<br/>M8</th>
<th id="h_M1" width=2%>cd<br/>M1</th>
<th id="h_M2" width=5%>N°<br/>M2</th>
<th id="h_M4" width=23%>Désignation<br/>M4</th>
<th id="h_M7" width=3%>Uté<br/>M7</th>
<th id="h_M9" width=3%>Qté <br/>M9</th>
<th id="h_M18" width=5%>PR Fourniture unitaire<br/>M18</th>
<th id="h_M20" width=3%>Type FO<br/>M20</th>
<th id="h_M14" width=3%>K Acc<br/>M14</th>
<th id="h_M19" width=6%>PR Total fourniture<br/>M19</th>
<th id="h_M23" width=5%>Tps pose unitaire<br/>M23</th>
<th id="h_M26" width=3%>Type MO<br/>M26</th>
<th id="h_M22" width=3%>K Pose<br/>M22</th>
<th id="h_M42" width=5%>Tps pose total<br/>M42</th>
<th id="h_M40" width=5%>PR unitaire<br/>M40</th>
<th id="h_M41" width=5%>PR Total<br/>M41</th>
<th id="h_M27" width=3%>qte vendue<br/>M27</th>
<th id="h_M32" width=5%>PV unitaire<br/>M32</th>
<th id="h_M44" width=6%>PV Total<br/>M44</th>
</thead>
<tbody>
<tr class="parent" data-level="0">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">1</td>
<td headers="h_M2">A</td>
<td headers="h_M4">Titre 1, n'appartient à personne</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
<td headers="h_M18"></td>
<td headers="h_M20"></td>
<td headers="h_M14"></td>
<td headers="h_M19"></td>
<td headers="h_M23"></td>
<td headers="h_M26"></td>
<td headers="h_M22"></td>
<td headers="h_M42"></td>
<td headers="h_M40"></td>
<td headers="h_M41"></td>
<td headers="h_M27"></td>
<td headers="h_M32"></td>
<td headers="h_M44"></td>
</tr>
<tr class="parent" data-level="1">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">2</td>
<td headers="h_M2">A.1</td>
<td headers="h_M4">Titre 2 - la ligne doit appartenir au titre niveau 1, N°A ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="child" data-level="2">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne "terminale" doit appartenir au titre niveau 2, N°A.1 ci-dessus</td>
<td headers="h_M7">km</td>
<td headers="h_M9">6</td>
</tr>
<tr class="child" data-level="2">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne doit aussi appartenir au titre niveau 2, N°A.1 ci-dessus</td>
<td headers="h_M7">m</td>
<td headers="h_M9">10,5</td>
</tr>
<tr class="parent" data-level="0">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">1</td>
<td headers="h_M2">B</td>
<td headers="h_M4">un autre Titre 1, n'appartient à personne</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="parent" data-level="1">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">2</td>
<td headers="h_M2">B.1</td>
<td headers="h_M4">Titre 2 - la ligne doit appartenir au titre niveau 1, N°B ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="parent" data-level="2">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">3</td>
<td headers="h_M2">B.1.1</td>
<td headers="h_M4">Titre 3 - la ligne doit appartenir au titre niveau 2, N°B.1 ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="child" data-level="3">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne "terminale" doit appartenir au titre niveau 3, N°B.1.1 ci-dessus</td>
<td headers="h_M7">kg</td>
<td headers="h_M9">2</td>
</tr>
<tr class="child" data-level="3">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne doit aussi appartenir au titre niveau 3, N°B.1.1 ci-dessus</td>
<td headers="h_M7">m</td>
<td headers="h_M9">10,5</td>
</tr>
<tr class="child" data-level="2">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">3</td>
<td headers="h_M2">B.1.2</td>
<td headers="h_M4">Titre 3 - la ligne doit appartenir au titre niveau 2, N°B.1 ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
</tbody>
</table>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="voctor.js"></script>
</body>
</html>
如果我正确理解了您的问题,您希望能够在不打开 children 的情况下打开“parent”。
但是,您为什么要编写代码来这样做?
查看下面代码中的罪魁祸首:
var children = getChildren($(this).parent('.parent'));
$.each(children, function() {
if(action == "show") {
/* HERE : This line only purpose is to display the children when a parent is displayed */
$(this).removeClass('collapsed').show(); // <-- DELETE THIS
} else {
$(this).addClass('collapsed').hide();
if($(this).children('.colex').text() == '+') { // Replace possible '+' by a '-' when parent's collapsed //
$(this).children('.colex').text('-');
}
}
});
编辑:
由于您的要求已更改,您需要检查您的逻辑。
我们知道的:
- 只有 parent 可以折叠
- 打开 parent 应该只会显示它们的直接 children 和之前未隐藏的 sub-children
要实现此行为,我们需要区分折叠的 parent 和隐藏的 children。
查看代码中的变化:
var level = $(this).parent('.parent').attr('data-level');
var children = getChildren($(this).parent('.parent'));
$.each(children, function() {
if(action == "show") {
if ($(this).attr('data-level')==parseInt(level)+1
|| $(this).hasClass('hidden')===false) {
/* un-hide direct children, and not hidden sub-children */
$(this).removeClass('hidden').show();
}
} else {
if ($(this).attr('data-level')==parseInt(level)+1) {
/* apply hidden to direct children */
$(this).addClass('hidden');
}
/* hide all children */
$(this).hide();
}
});
如果你想测试它,我用新代码编辑了你的 Fiddle。
我还用一行替换了你的多个 if
语句:
$(cells).parent().addClass('Titre_'+cells[2].innerHTML);
我正在尝试为一个项目制作一个可折叠的 table,到目前为止,我做得很好。我只遇到一个我不知道如何处理的问题:实际上我的可折叠行(有子行的行)正在折叠,但是如果我折叠一个子行,然后折叠父行,然后展开父行,则children 也被扩展了。如何保存子项的状态,以便在我们展开父项时它们不会展开?
$(document).ready(function() {
// Define color depending on the M1 cell value //
var rows = document.getElementsByTagName("tbody")
[0].getElementsByTagName("tr");
// loops through each row
for (i = 0; i < rows.length; i++) {
cells = rows[i].getElementsByTagName('td');
if (cells[2].innerHTML == '1')
$(cells).parent().addClass('Titre_1');
if (cells[2].innerHTML == '2')
$(cells).parent().addClass('Titre_2');
if (cells[2].innerHTML == '3')
$(cells).parent().addClass('Titre_3');
if (cells[2].innerHTML == '4')
$(cells).parent().addClass('Titre_4');
if (cells[2].innerHTML == '5')
$(cells).parent().addClass('Titre_5');
if (cells[2].innerHTML == '6')
$(cells).parent().addClass('Titre_6');
if (cells[2].innerHTML == '7')
$(cells).parent().addClass('Titre_7');
if (cells[2].innerHTML == '8')
$(cells).parent().addClass('Titre_8');
if (cells[2].innerHTML == '9')
$(cells).parent().addClass('Titre_9');
}
// Expand/collapse when clicking on first column //
function getChildren($row) {
var children = [], level = $row.attr('data-level');
while($row.next().attr('data-level') > level) {
children.push($row.next());
$row = $row.next();
}
return children;
}
$('.colex').on('click', function() {
var action;
if($(this).parent('.parent').hasClass('collapsed')) {
$(this).parent('.parent').removeClass('collapsed');
$(this).text('-');
action = 'show';
} else {
$(this).parent('.parent').addClass('collapsed');
$(this).text('+');
action = 'hide';
}
var children = getChildren($(this).parent('.parent'));
$.each(children, function() {
if(action == "show") {
$(this).removeClass('collapsed').show();
} else {
$(this).addClass('collapsed').hide();
if($(this).children('.colex').text() == '+') { // Replace possible '+' by a '-' when parent's collapsed //
$(this).children('.colex').text('-');
}
}
});
})
})
body {
font-family: sans-serif;
}
body * {
box-sizing: border-box;
/*color: #59547c;*/
margin: 0;
}
main {
/* max-width: 60rem;*/
margin: 1px auto;
padding: 1rem;
}
h1 {
margin-bottom: 1rem;
}
p {
margin-bottom: 1rem;
}
input.variante[type=checkbox] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
input.variante[type=checkbox] {
height: 15px;
width: 15px;
background: #fff;
border: 1px solid #ccc;
}
input.variante[type="checkbox"]:checked
{
background: orange;
&:before {
font-family: FontAwesome;
content: '\f00c';
display: block;
color: grey;
font-size: 15px;
position: absolute;
}
}
table {
empty-cells: show;
}
th {
text-align:center;
border: 1px solid antiquewhite;
}
.parent > .colex {
color: black;
cursor: pointer;
}
.table_header {
background-color:#484e82;
color:#fdfdff;
font-weight: bold;
}
.intro {
font-size: 1.125rem;
}
.Titre_1 {
color: red;
}
.Titre_2 {
color: purple;
}
.Titre_3 {
color: fuchsia;
}
.Titre_4 {
color: green;
}
.Titre_5 {
color: lime;
}
.Titre_6 {
color: navy;
}
.Titre_7 {
color: blue;
}
.Titre_8 {
color: aqua;
}
.Titre_9 {
color: orange;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Devis</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<intro>
<p class="intro">description</p>
</intro>
<main>
<table id="mytable" align=center rules=groups frame=box hborder=0 cellspacing=1 cellpadding=4 vborder=1>
<thead class="table_header">
<th id="colex" width=2%>Co<br/>Ex</th>
<th id="h_M8" width=2%>V<br/>M8</th>
<th id="h_M1" width=2%>cd<br/>M1</th>
<th id="h_M2" width=5%>N°<br/>M2</th>
<th id="h_M4" width=23%>Désignation<br/>M4</th>
<th id="h_M7" width=3%>Uté<br/>M7</th>
<th id="h_M9" width=3%>Qté <br/>M9</th>
<th id="h_M18" width=5%>PR Fourniture unitaire<br/>M18</th>
<th id="h_M20" width=3%>Type FO<br/>M20</th>
<th id="h_M14" width=3%>K Acc<br/>M14</th>
<th id="h_M19" width=6%>PR Total fourniture<br/>M19</th>
<th id="h_M23" width=5%>Tps pose unitaire<br/>M23</th>
<th id="h_M26" width=3%>Type MO<br/>M26</th>
<th id="h_M22" width=3%>K Pose<br/>M22</th>
<th id="h_M42" width=5%>Tps pose total<br/>M42</th>
<th id="h_M40" width=5%>PR unitaire<br/>M40</th>
<th id="h_M41" width=5%>PR Total<br/>M41</th>
<th id="h_M27" width=3%>qte vendue<br/>M27</th>
<th id="h_M32" width=5%>PV unitaire<br/>M32</th>
<th id="h_M44" width=6%>PV Total<br/>M44</th>
</thead>
<tbody>
<tr class="parent" data-level="0">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">1</td>
<td headers="h_M2">A</td>
<td headers="h_M4">Titre 1, n'appartient à personne</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
<td headers="h_M18"></td>
<td headers="h_M20"></td>
<td headers="h_M14"></td>
<td headers="h_M19"></td>
<td headers="h_M23"></td>
<td headers="h_M26"></td>
<td headers="h_M22"></td>
<td headers="h_M42"></td>
<td headers="h_M40"></td>
<td headers="h_M41"></td>
<td headers="h_M27"></td>
<td headers="h_M32"></td>
<td headers="h_M44"></td>
</tr>
<tr class="parent" data-level="1">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">2</td>
<td headers="h_M2">A.1</td>
<td headers="h_M4">Titre 2 - la ligne doit appartenir au titre niveau 1, N°A ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="child" data-level="2">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne "terminale" doit appartenir au titre niveau 2, N°A.1 ci-dessus</td>
<td headers="h_M7">km</td>
<td headers="h_M9">6</td>
</tr>
<tr class="child" data-level="2">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne doit aussi appartenir au titre niveau 2, N°A.1 ci-dessus</td>
<td headers="h_M7">m</td>
<td headers="h_M9">10,5</td>
</tr>
<tr class="parent" data-level="0">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">1</td>
<td headers="h_M2">B</td>
<td headers="h_M4">un autre Titre 1, n'appartient à personne</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="parent" data-level="1">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">2</td>
<td headers="h_M2">B.1</td>
<td headers="h_M4">Titre 2 - la ligne doit appartenir au titre niveau 1, N°B ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="parent" data-level="2">
<td headers="colex" class="colex">-</td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">3</td>
<td headers="h_M2">B.1.1</td>
<td headers="h_M4">Titre 3 - la ligne doit appartenir au titre niveau 2, N°B.1 ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
<tr class="child" data-level="3">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne "terminale" doit appartenir au titre niveau 3, N°B.1.1 ci-dessus</td>
<td headers="h_M7">kg</td>
<td headers="h_M9">2</td>
</tr>
<tr class="child" data-level="3">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">9</td>
<td headers="h_M2"></td>
<td headers="h_M4">cette ligne doit aussi appartenir au titre niveau 3, N°B.1.1 ci-dessus</td>
<td headers="h_M7">m</td>
<td headers="h_M9">10,5</td>
</tr>
<tr class="child" data-level="2">
<td headers="colex" class="colex"></td>
<td headers="h_M8"><input class="variante" type="checkbox"></td>
<td headers="h_M1">3</td>
<td headers="h_M2">B.1.2</td>
<td headers="h_M4">Titre 3 - la ligne doit appartenir au titre niveau 2, N°B.1 ci-dessus</td>
<td headers="h_M7">ens</td>
<td headers="h_M9">1</td>
</tr>
</tbody>
</table>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="voctor.js"></script>
</body>
</html>
如果我正确理解了您的问题,您希望能够在不打开 children 的情况下打开“parent”。
但是,您为什么要编写代码来这样做?
查看下面代码中的罪魁祸首:
var children = getChildren($(this).parent('.parent'));
$.each(children, function() {
if(action == "show") {
/* HERE : This line only purpose is to display the children when a parent is displayed */
$(this).removeClass('collapsed').show(); // <-- DELETE THIS
} else {
$(this).addClass('collapsed').hide();
if($(this).children('.colex').text() == '+') { // Replace possible '+' by a '-' when parent's collapsed //
$(this).children('.colex').text('-');
}
}
});
编辑: 由于您的要求已更改,您需要检查您的逻辑。
我们知道的:
- 只有 parent 可以折叠
- 打开 parent 应该只会显示它们的直接 children 和之前未隐藏的 sub-children
要实现此行为,我们需要区分折叠的 parent 和隐藏的 children。
查看代码中的变化:
var level = $(this).parent('.parent').attr('data-level');
var children = getChildren($(this).parent('.parent'));
$.each(children, function() {
if(action == "show") {
if ($(this).attr('data-level')==parseInt(level)+1
|| $(this).hasClass('hidden')===false) {
/* un-hide direct children, and not hidden sub-children */
$(this).removeClass('hidden').show();
}
} else {
if ($(this).attr('data-level')==parseInt(level)+1) {
/* apply hidden to direct children */
$(this).addClass('hidden');
}
/* hide all children */
$(this).hide();
}
});
如果你想测试它,我用新代码编辑了你的 Fiddle。
我还用一行替换了你的多个 if
语句:
$(cells).parent().addClass('Titre_'+cells[2].innerHTML);