【问题标题】:Numbering h1,h2 headings, nested documents that reset counter编号 h1,h2 标题,重置计数器的嵌套文档
【发布时间】:2021-11-15 15:01:51
【问题描述】:

我希望在下面的标题中添加数字。问题是有些文档可能无限嵌套,需要独立统计。在原始文档中,标题仅为文本,没有编号前缀。

<div id="text_output">
  <h1>Document 1</h1>
    <h2>1 Heading</h2>
      <h3>1.1 Subheading</h3>
      <h3>1.2 Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document 2</h1>
            <h2>1 Heading</h2>
              <h3>1.1 Subheading</h3>
            <h2>2 Heading</h2>
              <h3>2.1 Subheading</h3>
        </div>
      <h3>1.3 Subheading</h3>
    <h2>2 Heading</h2>
      <h3>2.1 Subheading</h3>
      <h3>2.2 Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document 3</h1>
            <h2>1 Heading</h2>
              <h3>1.1 Subheading</h3>
            <h2>2 Heading</h2>
              <h3>2.1 Subheading</h3>
                <div class="text_output_expansion">
                  <h1>Document 4</h1>
                    <h2>1 Heading</h2>
                      <h3>1.1 Subheading</h3>
                    <h2>2 Heading</h2>
                      <h3>2.1 Subheading</h3>
                </div>
              <h3>2.2 Subheading</h3>
        </div>
      <h3>2.3 Subheading</h3>
    <h2>3 Heading</h2>
      <h3>3.1 Subheading</h3>
      <h3>3.2 Subheading</h3>
</div>

我将发布一个 CSS 解决方案,但我只是在努力让它在 javascript 中工作。这个想法是这样我就可以复制和粘贴带有完整数字的文档(CSS 解决方案不允许这样做)。诚然,我的 javascript 不是很好,但我的挣扎似乎是 js 如何从上到下循环遍历元素。

【问题讨论】:

  • 您的意见是什么? DOM 节点? HTML 文本?那么输出呢?你能分享一些你自己在这方面的尝试吗?
  • 您的缩进意味着文档中不存在嵌套。是否有可能改变结构,例如,第二个H3 嵌套在下面的DIV 中,或者一些通用元素将它们都包裹起来?
  • 不幸的是结构被锁定,我正在使用别人的数据,我认为这些数据来自 Markdown 文件。
  • 那么你能改变你对输出的期望吗?在我看来,真正的问题是 1.3 副标题在视觉上看起来好像嵌套在 Document 2 &gt; 2 Heading 2 下,紧跟在 2.1 Subheading 之后并处于同一水平。这将是非常令人困惑的。将嵌套标题更改为属于其父层次结构怎么样?也就是说,第一个text_output_expansion 下的标题可能会变成H4H5H6H5H6,然后看起来它们是正确嵌套的。问题是当你点击H8 时,我想你会的,但必须付出一些代价。

标签: javascript html jquery css recursion


【解决方案1】:

您可以通过对h标签块进行分组来递归遍历结构:

var div = document.createElement("div");
div.innerHTML = `<div id="text_output">
  <h1>Document</h1>
    <h2>Heading</h2>
      <h3>Subheading</h3>
      <h3>Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document</h1>
            <h2>Heading</h2>
              <h3>Subheading</h3>
            <h2>Heading</h2>
              <h3>Subheading</h3>
        </div>
      <h3>Subheading</h3>
    <h2>Heading</h2>
      <h3>Subheading</h3>
      <h3>Subheading</h3>
        <div class="text_output_expansion">
          <h1>Document</h1>
            <h2>Heading</h2>
              <h3>Subheading</h3>
            <h2>Heading</h2>
              <h3>Subheading</h3>
                <div class="text_output_expansion">
                  <h1>Document</h1>
                    <h2>Heading</h2>
                      <h3>Subheading</h3>
                    <h2>Heading</h2>
                      <h3>Subheading</h3>
                </div>
              <h3>Subheading</h3>
        </div>
      <h3>Subheading</h3>
    <h2>Heading</h2>
      <h3>Subheading</h3>
      <h3>Subheading</h3>
</div>`
document.querySelector('body').appendChild(div)

function number_headings(root){
    var h1 = 1;
    function label_headings(nodes, p){
       var [groups, group, h] = [[], [], null]
       for (var i of nodes){
          if (i.tagName[0].toLowerCase() != 'h' || (h != null && i.tagName != h.tagName)){
             group.push(i)
          }
          else if (h === null){
             h = i;
          }
          else{
             groups.push({node:h, block:group.slice()});
             group = [];
             h = i;
          }
       }
       if (h != null){
          groups.push({node:h, block:group.slice()});
       }
       var c = 1;
       for ({node:n, block:b} of groups){
           if (n.tagName === 'H1'){
              n.textContent = `${n.textContent} ${h1}`;
              h1++;
           }
           else{
              n.textContent = `${(p === null ? c.toString() : p+'.'+c.toString())} ${n.textContent}`;
           }
           label_headings(b, n.tagName === 'H1' ? null : (p === null ? '':p+'.')+c.toString());
           for (var k of b.filter(function(x){return x.nodeType === 1 && x.tagName[0] != "H"})){
              label_headings(Array.from(k.childNodes).filter(function(x){return x.nodeType === 1}), null);
           }
           c++;
       }
    }
    label_headings(Array.from(root.childNodes).filter(function(x){return x.nodeType === 1}))
}
number_headings(document.querySelector('#text_output'), null)

【讨论】:

    【解决方案2】:

    一种解决方案是使用 CSS 计数器将文本附加到标题中。不幸的是,这种方法的弱点(或优势)在于它对用户可见,但不能从浏览器复制粘贴,如果您在脚本的其他地方需要它,也不容易获得该值。

    #text_output {
      counter-reset: h2
    }
    
    #text_output h2 {
      counter-reset: h3
    }
    
    #text_output .text_output_expansion .card-body{
      counter-reset: h2
    }
    
    #text_output .text_output_expansion .card-body h2 {
      counter-reset: h3
    }
    
    #text_output h2:before {
      counter-increment: h2;
      content: counter(h2) ". "
    }
    
    #text_output h3:before,
    h3.md-focus.md-heading:before {
      counter-increment: h3;
      content: counter(h2) "."counter(h3) ". "
    }
    
    

    【讨论】:

      【解决方案3】:

      做了另一个递归选项。我认为 Ajax 有最好的答案!

      function numberHeadings(element) {
      var h1_counter = 0;
      var h2_counter = 0;
      var h3_counter = 0;
      var h4_counter = 0;
      var h5_counter = 0;
      var h6_counter = 0;
      element.find(".text_output_expansion").each(function () {
        numberHeadings($(this));
      });
      
      element.find("h1:not([numberHeadings=complete]),h2:not([numberHeadings=complete]),h3:not([numberHeadings=complete]),h4:not([numberHeadings=complete]),h5:not([numberHeadings=complete]),h6:not([numberHeadings=complete])").each(function () {
        switch ($(this).prop("tagName")) {
          case "H1":
            h1_counter += 1;
            h2_counter = 0;
            h3_counter = 0;
            h4_counter = 0;
            h5_counter = 0;
            h6_counter = 0;
            $(this).text(h1_counter.toString() + ". " + $(this).text());
            $(this).attr("numberHeadings", "complete");
            break;
          case "H2":
            h2_counter += 1;
            h3_counter = 0;
            h4_counter = 0;
            h5_counter = 0;
            h6_counter = 0;
            $(this).text(h1_counter.toString() + "." + h2_counter.toString() + ". " + $(this).text());
            $(this).attr("numberHeadings", "complete");
            break;
          case "H3":
            h3_counter += 1;
            h4_counter = 0;
            h5_counter = 0;
            h6_counter = 0;
            $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + ". " + $(this).text());
            $(this).attr("numberHeadings", "complete");
            break;
          case "H4":
            h4_counter += 1;
            h5_counter = 0;
            h6_counter = 0;
            $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + "." + h4_counter.toString() + ". " + $(this).text());
            $(this).attr("numberHeadings", "complete");
            break;
          case "H5":
            h5_counter += 1;
            h6_counter = 0;
            $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + "." + h4_counter.toString() + "." + h5_counter.toString() + ". " + $(this).text());
            $(this).attr("numberHeadings", "complete");
            break;
          case "H6":
            h6_counter += 1;
            $(this).text(h1_counter.toString() + "." + h2_counter.toString() + "." + h3_counter.toString() + "." + h4_counter.toString() + "." + h5_counter.toString() + "." + h6_counter.toString() + ". " + $(this).text());
            $(this).attr("numberHeadings", "complete");
            break;
        }
      })
      

      };

      【讨论】:

        猜你喜欢
        • 2010-11-12
        • 2019-01-02
        • 1970-01-01
        • 1970-01-01
        • 2013-01-14
        • 2012-09-17
        • 1970-01-01
        • 2011-06-13
        • 2021-06-22
        相关资源
        最近更新 更多