我开发了点击父节点以显示其子行。我只需要启用单击子数据应该打开其子子行作为递归的一个或表树。任何人都可以添加你的逻辑,这将帮助我理解并帮助他人吗?
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;
答案 0 :(得分:1)
更新回答
我几乎改变了所有内容并简化了代码:
我在GitHub上创建了一个包含该代码的存储库:
https://github.com/TakitIsy/table-to-tree
/* ---- < 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;
⋅ ⋅ ⋅
旧答案
我用你的代码玩了一点......
尝试尽可能多地使用现有的函数/方法,使代码更清晰,更易于阅读和理解。
...并以该片段结束:
(有关详细信息,请参阅我的代码中的注释)
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;
我希望它有所帮助!