仅使用 JavaScript 的递归 HTML 表格树

2024-02-11

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

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>

更新答案

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

  • 切换按钮会自动添加,
  • + changes to - when the parent is opened,
  • 表、打开和可见元素的类以及按钮作为参数传递,
  • 它可以在多个表上使用,

我已经在 GitHub 上使用该代码创建了一个存储库:
https://github.com/TakitIsy/table-to-tree 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>');
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: "[‒]";
}
<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>

⋅ ⋅ ⋅

旧答案

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

……最后得到了这个片段:
(有关更多详细信息,请参阅我的代码中的注释)

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");
  });
});
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;
}
<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>

我希望它有帮助!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅使用 JavaScript 的递归 HTML 表格树 的相关文章

  • 使用 css 简单地将对象居中,无需修改

    我想使用 CSS 将对象居中 而不需要任何技巧 这可能吗 如何实现 我已经尝试过了 但是我的 p 标签消失了 centered position fixed top 50 left 50 有多种方法可以使元素居中 但这取决于您的元素是什么以
  • Chrome 中的性能问题

    我目前正在从事一个相对较大的项目 使用 AngularJs 构建 应用程序的一部分是一个表单 您可以向其中添加任意数量的页面 不幸的是 添加了很多不必要的垃圾 即表示表单模型的对象可能会变得非常大 在某些时候 Chrome 基本上无法处理它
  • Twitter 卡元标签问题

    有问题的网址 https www halleonard com viewpressreleasedetail action releaseid 10261 https www halleonard com viewpressreleased
  • 图像无法在带有 DOM 的 IE 中加载:控制台中的 7009 错误(无法解码)

    当在 IE 中的单个页面上加载许多图像时 在 IE11 中重现 其中一些图像开始加载失败 并在控制台中出现类似以下警告的内容 DOM7009 无法解码 URL 处的图像 某些唯一的 url 当我查看网络流量时 似乎确实从服务器收到了每个图像
  • 如何针对 Node.js 中发生的每个错误发送电子邮件?

    假设我的 node js 应用程序正在运行 如果出现错误 我的意思是所有错误 不仅仅是网络错误 如果出现错误 则很重要 我如何调用函数向我发送电子邮件 基本上 在我希望它写入 err out 之前 我希望向我发送一封电子邮件 我正在使用no
  • 将 GMT 时间转换为当地时间

    我以这种格式从我的服务器获取 GMT 时间 Fri 18 Oct 2013 11 38 23 GMT 我的要求是使用Javascript将此时间转换为本地时间 例如 如果用户来自印度 首先我需要采用时区 5 30并将其添加到我的服务器时间并
  • 调整图像大小并将画布旋转 90 度

    这里有很多关于在 js 上使用画布旋转图像的主题 我阅读了其中的大部分内容 但无法找到解决我的问题的方法 我正在接收任何分辨率的图像 来自上传组件 我将其大小调整为 1024x768 如下所示 var canvas document cre
  • 如何解决 Typescript 构建中的错误“找不到模块 'jquery'”

    我目前在 ts 文件的顶部有这个import require jquery 我这样做是因为我试图在我的打字稿文件中使用 jquery 但我似乎无法编译它 因为它返回标题中所述的错误 我正在使用 ASP NET CORE 脚本文件夹 tsco
  • window.location 和 location.href 之间的区别

    我对之间的区别感到困惑window location and location href 两者似乎都以相同的方式行事 有什么不同 window location是一个对象 它保存有关当前文档位置的所有信息 主机 href 端口 协议等 lo
  • DataTables row.add 到特定索引

    我正在替换这样的行项目 var targetRow entity row dataTable targetRow closest table dataTable DataTable dataTable row targetRow remov
  • 不可勾选的单选按钮与专有的复选框

    从 UI 角度来看 是拥有一组具有取消选中功能的单选按钮更好 还是拥有一组独占的复选框 意味着一次只能选中一个 更好 Update 我没想到对此会有如此负面的反应 如果我给出一个更接近其使用方式的示例 也许会有所帮助 我有一个充满数据绑定内
  • 页面上使用 HTML Editor Extender 进行回发会导致 IE11 中出现 JavaScript 错误

    我已将 HTML 编辑器扩展程序添加到我正在处理的页面中 现在每当我在页面上发回帖子时 都会收到以下 Javascript 错误 JavaScript 运行时错误 参数无效 之后什么也没有发生 这在 IE10 或更低版本以及我所知道的所有其
  • Firebase 函数 onWrite 未被调用

    我正在尝试使用 Firebase 函数实现一个触发器 该触发器会复制数据库中的一些数据 我想观看所有添加的内容votes user vote 结构为 我尝试的代码是 const functions require firebase func
  • 从数据库检查数据的异步解决方案各种循环子句

    我想要做的是异步检查数据库并从中获取结果 在我的应用程序中我试图实现Asynchronously将此步骤解决为 从数据库中检查手机号码JsonArray循环子句的种类 Create JsonArray从结果 打印创建的数组 我学到了足够多的
  • 如何创建适合屏幕宽度的等宽/高框? [复制]

    这个问题在这里已经有答案了 我正在尝试建立一个网站 其中有很多宽度和高度相等的框 例如 我有一个页面 其中并排有两个相同大小的框 简单的解决方案是将宽度和高度设置为 50vw 这在出现滚动条之前效果很好 我已经用谷歌搜索了几个小时 但无法理
  • Javascript - 水波纹效果

    我需要 JS 上的脚本 它将以 水波纹 样式更改 images html 抱歉 6MB GIF 文件 http fcuunited ru temp listening2 gif http fcunited ru temp listening
  • HTML 锚点,禁用样式

    我有一些 html 锚链接代码 与文档的其余部分不同 我希望它看起来不是链接 有没有一种简单的方法可以禁用由于将文本包装在锚标记中而引起的样式更改 而不必强行使其相同 即 如果我更改正文字体样式 我不必也更改其他一些 link东西 将颜色设
  • JavaScript 相对路径

    在第一个 html 文件中 我使用了一个变量类别链接 var categoryLinks Career prospects http localhost Landa DirectManagers 511 HelenaChechik Dim0
  • CSS溢出文本显示在几行中,没有断字

    我有一些长文本显示在 div 中 该 div 具有固定的宽度和高度 我希望文本显示在几行上 作为 div 高度 并且句子单词不会中断 一行中的单词前缀和下一行中的继续 此外 我想在末尾添加省略号最后一句话 CSS white space n
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • 下载 Azure Web 应用程序?

    我刚刚开设了一个免费的 Azure 试用帐户 并通过各种表格创建了一个测试 Web 应用程序 但是 我想使用 Visual Studio 2015 在本地编辑源文件 是否可以下载注册期间生成的文件 如果可以 如何下载 谢谢你的帮助 您可以使
  • 如何将可变宽度的浮动元素水平居中?

    如何将可变宽度的浮动元素水平居中 编辑 我已经使用包含的div对于浮动元素并指定width对于容器 然后使用margin 0 auto 对于容器 我只是想知道是否可以在不使用包含元素的情况下完成 或者至少不需要指定width对于包含元素 假
  • 编写拼字游戏的算法

    我正在研究一个类似填字游戏的问题 但我不知道如何设计算法 例如 字典里有 汽车 苹果 等词 黑板上给出了 app 一词 有像 l e c r 这样的字母用于造词 所以算法的任务是生成存储在字典中的正确单词 app gt lapp gt le
  • 如何检查字符串是否为数字 Julia

    一直在互联网上搜索试图弄清楚这一点 尝试过isnumeric 但这仅适用于AbstractChar 我宁愿不用tryparse如果可能的话 但如果这是唯一的解决方案 那就这样吧 如果是的话 为什么还没有实现检查字符串是否为数字的函数 我发现
  • BasicAuth、OAuth 和 XAuth 之间有什么区别?

    最近我听说 Twitter 将关闭 Twitter API 上的基本身份验证 并转向 OAuth 所以我想知道BasicAuth OAuth 和XAuth 之间有什么区别 每个 Auth 的优点和缺点是什么 xAuth 是 OAuth 的简
  • 如何将Rtools\bin添加到R中的系统路径

    我正在运行一个闪亮的应用程序https github com MikeJSeo SAM https github com MikeJSeo SAM以及访问它的代码 install packages c samr matrixStats GS
  • Google Analytics Gtag 多个 Analytics 帐户跟踪 ID

    据我所知 谷歌现在似乎正在逐步淘汰analytics js 转而使用他们的标签管理器 如何为多个分析帐户触发 Google Analytics 新的 gtag 跟踪代码 像这样的事情
  • ggplot:根据用户定义的颜色按组划分颜色点

    我试图定义 ggplot 中绘制的点组的颜色 我改编了这篇文章的代码 根据定义的颜色代码为 ggplot 点着色 https stackoverflow com questions 9827193 color ggplot points b
  • NuSOAP 和数组响应

    我有 NuSOAP 网络服务器 server gt register getMembersEvents array date gt xsd string array Events gt tns Events urn my false rpc
  • R:如何读取列线图来预测所需的变量

    我正在使用 Rstudio 我使用函数创建了列线图nomogram从包装中rms使用以下代码 从示例代码复制文档 http www inside r org packages cran rms docs nomogram library r
  • 如何删除闪亮的renderUI中的输入?

    在我闪亮的应用程序中 我有一个使用 renderUI 的动态输入 这工作得很好 程序的另一部分捕获滑块的输入 当应用程序状态发生变化时 例如 当按下 更新模型 按钮时 我仍然需要显示 使用具有类似标签的滑块 但由于它们是 新的 因此需要将值
  • 如何延迟 html 文本的显示,直到加载背景图像精灵?

    这是我想使用 jQuery 控制的一些示例代码 黑色页面背景上的白色按钮背景 ul class buttons li class button displays a href products Products and Services f
  • 连接语句省略条目

    使用 Unix 2 6 18 194 el5 我遇到一个问题 该连接语句省略了匹配中的值 索引 我发现这些值在 11 90 之间 大约 350 万个条目 并且我尝试查找外来字符 但我可能忽略了某些内容 尝试使用 cat v 来查看隐藏字符
  • 雾化T的.Net Collection?

    我正在寻找是否有一个预先存在的 Net 哈希集类型 实现适合原子化一般类型 T 我们有大量相同的对象用于序列化源 需要原子化以节省内存 A Dictionary
  • union '双关语'结构带有“公共初始序列”:为什么 C (99+) 而不是 C++ 规定了“联合类型的可见声明”?

    背景 通过以下方式讨论类型双关的大多数非或实现定义的性质union通常引用以下位 此处通过 ecatmur https stackoverflow com a 31557852 2757035 https stackoverflow com
  • Angular 2 - 警告/提示的表单验证

    我正在尝试添加不会使表单无效的表单验证 验证应仅显示为警告 例如 年龄验证 年龄大于 90 表示警告 年龄大于 120 表示错误 我已经尝试过在表单上使用两个 FormGroup 并在输入字段上使用两个 formControl 仅使用第一个
  • 正确管理addObserverForName:object:queue:usingBlock:

    我对 Objective C 中的块仍然很陌生 想知道我的伪代码是否正确 我不确定仅删除观察者是否足够 或者是否必须调用removeObserver name object void scan Scanner scanner Scanner
  • 使用 Powershell 将 EBS 卷附加到 Windows EC2 [关闭]

    Closed 这个问题是与编程或软件开发无关 help closed questions 目前不接受答案 我看到很多关于在 Linux 上添加 EBS 卷的问题得到了解答 但在 Windows 上却没有 假设您发现磁盘空间不足 可能通过 C
  • 带通配符的 spring

    我想从多个位置加载键值对 我的第一个猜测是
  • 仅使用 JavaScript 的递归 HTML 表格树

    我开发了单击父节点来显示其子行 我只需要启用单击子数据即可将其子子行作为递归树或表树打开 有人可以添加你的逻辑来帮助我理解并帮助其他人吗 document getElementById products addEventListener c