仅使用JavaScript

时间:2018-05-22 18:03:07

标签: javascript html

我开发了点击父节点以显示其子行。我只需要启用单击子数据应该打开其子子行作为递归的一个或表树。任何人都可以添加你的逻辑,这将帮助我理解并帮助他人吗?



document.getElementById("products").addEventListener("click", function(e) {
    if (e.target.tagName === "A") {
        e.preventDefault();
        var row = e.target.parentNode.parentNode;
        while ((row = nextTr(row)) && !/\bparent\b/ .test(row.className))
            toggle_it(row);
    }
});

function nextTr(row) {
    while ((row = row.nextSibling) && row.nodeType != 1);
    return row;
}

function toggle_it(item){ 
     if (/\bopen\b/.test(item.className))
         item.className = item.className.replace(/\bopen\b/," ");
     else
         item.className += " open";
 } 

tbody tr {
    display : none;
}
tr.parent {
    display : table-row;
}
tr.open {
    display : table-row;
}

<!-- 
  Bootstrap docs: https://getbootstrap.com/docs
-->

<div class="container">
  <table class="table" id="products">
    <thead>
    <tr>
        <th>Product</th>
        <th>Price</th>
        <th>Destination</th>
        <th>Updated on</th>
    </tr>
    </thead>
    <tbody>
    <tr class="parent">
    <td><a href="#">+</a>Oranges</td>
        <td>100</td>
        <td>On Store</td>
        <td>22/10</td>
    </tr>
    <tr>
        <td>121</td>
        <td>120</td>
        <td>City 1</td>
        <td>22/10</td>
    </tr>
    <tr>
    <td>212</td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
    </tr>
    <tr>
    <td>212</td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
    </tr>
    <tr class="parent">
        <td><a href="#">+</a>Apples</td>
        <td>100</td>
        <td>On Store</td>
        <td>22/10</td>
    </tr>
    <tr>
        <td>120</td>
        <td>120</td>
        <td>City 1</td>
        <td>22/10</td>
    </tr>
    <tr>
        <td>120</td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
    </tr>
    </tbody>
</table>
   
</div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

更新回答

我几乎改变了所有内容并简化了代码:

  • 自动添加切换按钮
  • 打开父级时,
  • + 更改为 -
  • 表格,已打开和可见元素的类以及按钮作为参数传递,
  • 可以在多个表格上使用,
  • ...

我在GitHub上创建了一个包含该代码的存储库:
https://github.com/TakitIsy/table-to-tree

&#13;
&#13;
/* ---- < MAIN FUNCTION > ---- */
function tableToTree(table_Selector, tr_OpenedClass, tr_VisibleClass, tr_ToggleButton) {

  // Table elements variables
  var table = document.querySelector(table_Selector);
  var trs = document.querySelectorAll(table_Selector + " tr");

  // Add the buttons above the table
  var buttons = document.createElement('div');
  buttons.innerHTML = '<button>[‒] All</button><button>[+] All</button>';
  table.insertBefore(buttons, table.childNodes[0]);
  buttons = buttons.querySelectorAll('button');
  // Add the actions of these buttons
  buttons[0].addEventListener("click", function() {
    trs.forEach(function(elm) {
      elm.classList.remove(tr_OpenedClass);
      elm.classList.remove(tr_VisibleClass);
    });
  });
  buttons[1].addEventListener("click", function() {
    trs.forEach(function(elm) {
      if (elm.innerHTML.includes(tr_ToggleButton))
        elm.classList.add(tr_OpenedClass);
      elm.classList.add(tr_VisibleClass);
    });
  });

  // Next tr function
  function nextTr(row) {
    while ((row = row.nextSibling) && row.nodeType != 1);
    return row;
  }

  // On creation, automatically add toggle buttons if the tr has childs elements
  trs.forEach(function(tr, index) {
    if (index < trs.length - 1) {
      if (+tr.getAttribute("level") < +trs[index + 1].getAttribute("level")) {
        var elm1 = tr.firstElementChild;
        elm1.innerHTML = tr_ToggleButton + elm1.innerHTML;
      }
    }
  });

  // Use the buttons added by the function above
  table.addEventListener("click", function(e) {
    
    // Event management
    if (!e) return;
    if (e.target.outerHTML !== tr_ToggleButton) return;
    e.preventDefault();
    
    // Get the parent tr and its level
    var row = e.target.closest("tr");
    row.classList.toggle(tr_OpenedClass);
    var lvl = +(row.getAttribute("level"));

    // Loop to make childs visible/hidden
    while ((row = nextTr(row)) && ((+(row.getAttribute("level")) == (lvl + 1)) || row.className.includes(tr_VisibleClass))) {
      row.classList.remove(tr_OpenedClass);
      row.classList.toggle(tr_VisibleClass);
    }
  });

}
/* ---- </ MAIN FUNCTION > ---- */

// Call the above main function to make the table tree-like
tableToTree('#myTable', 'opened', 'visible', '<span class="toggle"></span>');
&#13;
tbody tr {
  display: none;
}

tr[level="0"],
tr.visible {
  display: table-row;
}

td {
  background: #ccc;
  padding: 4px 8px 4px 32px;
  text-align: left;
}

tr[level="1"] td {
  background: #ddd;
  padding-left: 40px;
}

tr[level="2"] td {
  background: #eee;
  padding-left: 48px;
}

tr .toggle {
  position: absolute;
  left: 16px;
  cursor: pointer;
}

.toggle::after {
  content: "[+]";
}

.opened .toggle::after {
  content: "[‒]";
}
&#13;
<table id="myTable">
  <tbody>
    <tr level="0">
      <td>Parent 1</td>
    </tr>
    <tr level="1">
      <td>Match 1</td>
    </tr>
    <tr level="1">
      <td>Match 2</td>
    </tr>
    <tr level="0">
      <td>Parent 2</td>
    </tr>
    <tr level="1">
      <td>Mismatch 1</td>
    </tr>
    <tr level="1">
      <td>Mismatch 2</td>
    </tr>
    <tr level="2">
      <td>Mismatch 2.1</td>
    </tr>
  </tbody>
</table>
<br>
&#13;
&#13;
&#13;

⋅ ⋅ ⋅

旧答案

我用你的代码玩了一点......
尝试尽可能多地使用现有的函数/方法,使代码更清晰,更易于阅读和理解。

...并以该片段结束:
(有关详细信息,请参阅我的代码中的注释)

&#13;
&#13;
document.getElementById("products").addEventListener("click", function(e) {
  // I think using the not equal is nicer here, just my opinion… Less indenting.
  if (!e) return;                       // Exit if null
  if (e.target.tagName !== "A") return; // Exit if not A element

  e.preventDefault();
  var row = e.target.closest("tr"); // Better than parent parent!
  var cls = row.classList[0];       // Get the first class name (the only one in our html)
  var lvl = +(cls.slice(-1)) + 1;   // Unary operator +1 on the last character
  cls = cls.slice(0, -1) + lvl;     // Replace the last char with lvl to get the class to be toggled

  // Check if the row is of the class to be displayed OR if the row is already opened
  // (so that clicking close on parent also closes sub-childs)
  while ((row = nextTr(row)) && (row.className.includes(cls) || row.className.includes("open")))
    row.classList.toggle("open"); // Better than the function you created, it already exists!
});

function nextTr(row) {
  while ((row = row.nextSibling) && row.nodeType != 1);
  return row;
}

// Select all the tr childs elements (all levels except 0
var allChilds = document.querySelectorAll("tr[class^=level]:not(.level0)");
// Added the below for buttons after comments
document.getElementById("openAll").addEventListener("click", function() {
  allChilds.forEach(function(elm){
    elm.classList.add("open");
  });
});
document.getElementById("closeAll").addEventListener("click", function() {
  allChilds.forEach(function(elm){
    elm.classList.remove("open");
  });
});
&#13;
tbody tr {
  display: none;
}


/* Simplified */

tr.level0,
tr.open {
  display: table-row;
}


/* Added colors for better visibility */

tr.level0 {
  background: #ccc;
}

tr.level1 {
  background: #ddd;
}

tr.level2 {
  background: #eee;
}


/* Added some more styling after comment */

tr td {
  padding: 0.2em 0.4em;
}

tr td:first-of-type {
  position: relative;
  padding: 0.2em 1em;
}

tr td a {
  color: inherit;
  /* No special color */
  text-decoration: inherit;
  /* No underline */
  position: absolute;
  left: 0.25em;
}

tr.level1 td:first-of-type {
  padding-left: 1.5em;
}

tr.level2 td:first-of-type {
  padding-left: 2em;
}
&#13;
<button id="openAll">+ All</button>
<button id="closeAll">- All</button>
<table class="table" id="products">
  <thead>
    <tr>
      <th>Product</th>
      <th>Price</th>
      <th>Destination</th>
      <th>Updated on</th>
    </tr>
  </thead>
  <tbody>
    <tr class="level0">
      <td><a href="#">+</a>Oranges</td>
      <td>100</td>
      <td>On Store</td>
      <td>22/10</td>
    </tr>
    <tr class="level1">
      <td>121</td>
      <td>120</td>
      <td>City 1</td>
      <td>22/10</td>
    </tr>
    <tr class="level1">
      <td><a href="#">+</a>212</td>
      <td>140</td>
      <td>City 2</td>
      <td>22/10</td>
    </tr>
    <tr class="level2">
      <td>212</td>
      <td>140</td>
      <td>City 2</td>
      <td>22/10</td>
    </tr>
    <tr class="level2">
      <td>212</td>
      <td>140</td>
      <td>City 2</td>
      <td>22/10</td>
    </tr>
    <tr class="level0">
      <td><a href="#">+</a>Apples</td>
      <td>100</td>
      <td>On Store</td>
      <td>22/10</td>
    </tr>
    <tr class="level1">
      <td>120</td>
      <td>120</td>
      <td>City 1</td>
      <td>22/10</td>
    </tr>
    <tr class="level1">
      <td><a href="#">+</a>120</td>
      <td>140</td>
      <td>City 2</td>
      <td>22/10</td>
      <tr class="level2">
        <td>120</td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
      </tr>
      <tr class="level2">
        <td>120</td>
        <td>140</td>
        <td>City 2</td>
        <td>22/10</td>
      </tr>
  </tbody>
</table>
&#13;
&#13;
&#13;

我希望它有所帮助!