如何保存折叠子行的状态(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> 

Here's the fiddle

如果我正确理解了您的问题,您希望能够在不打开 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);