首页 > 解决方案 > 在某些元素上从内部 for 循环重新开始编号

问题描述

我有一个插件,可以根据用户设置的自定义起始编号对标题标签进行编号。

它创建的标题如下:

1. Heading level one
1.1. Heading level two
1.1.1. Heading level three

如果用户手动设置起始编号:

20. Heading level one
20.3. Heading level two
20.3.6. Heading level three

但是,当循环重复时,编号不会重置为1,我似乎无法解决如何触发它:

20. Heading level one
20.3. Heading level two
20.3.6. Heading level three

20. Heading level one
20.4. Heading level two
20.4.6. Heading level three <-- this should renumber to 20.4.1

在第一个循环之后,我无法将以下代码段重置回1。我尝试过的一切都重置了所有迭代,导致header[3]设置为1但不仅在第一次迭代之后。

if( levelNumber <= elementLevel ) {
  numberText += startingNumbers[levelNumber] + ".";
}

测试代码

const header = [10, 20, 30, 40, 50, 60],
      contentHeaders = document.querySelectorAll(
        'h1, h2, h3, h4, h5, h6'
      ),
      startingNumbers   = [ 0,             // null
                            header[0] - 1, // h1
                            header[1] - 1, // h2
                            header[2] - 1, // h3
                            header[3] - 1, // h4
                            header[4] - 1, // h5
                            header[5] - 1, // h6
                          ];
for( var item in contentHeaders ) {

  // this element from item number
  var element = contentHeaders[item],
      numberText = '';

  // limit the heading tag number in search
  const headingRegex = new RegExp('^H([1-6])$');

  // does the element match a heading regex
  if( !element || !element.tagName || !element.tagName.match( headingRegex ) ) {
        // return to beginning of loop
        continue;
  }

  // return the heading level number
  var elementLevel = RegExp.$1;

  // increment by 1
  startingNumbers[elementLevel]++;
      
  // loop through the headings
  for( var levelNumber = 1; levelNumber <= 6; levelNumber++ ) {
        // if the number is lt the element number
        if( levelNumber <= elementLevel ) {
          numberText += startingNumbers[levelNumber] + ".";
        }
  }

  element.innerHTML =  numberText + ' ' + element.innerText;

}
* { font-family: monospace; font-size: 16px !important; }
<h1>Heading 1</h1>
<p>I should be <code>10. Heading 1</code></p>
<h2>Heading 2</h2>
<p>I should be <code>10.20. Heading 2</code></p>
<h3>Heading 3</h3>
<p>I should be <code>10.20.30. Heading 3</code></p>
<h4>Heading 4</h4>
<p>I should be <code>10.20.30.40. Heading 4</code></p>
<h5>Heading 5</h5>
<p>I should be <code>10.20.30.40.50. Heading 5</code></p>
<h6>Heading 6</h6>
<p>I should be <code>10.20.30.40.50.60. Heading 6</code></p>

<hr>

<h2>Heading 2</h2>
<p>I should be <code>10.21. Heading 2</code></p>
<h3>Heading 3</h3>
<p>I should be <code>10.21.1 Heading 3</code></p>

<hr>

<h2>Heading 2</h2>
<p>I should be <code>10.22. Heading 2</code></p>
<h3>Heading 3</h3>
<p>I should be <code>10.22.1. Heading 3</code></p>
<h4>Heading 4</h4>
<p>I should be <code>10.22.1.1. Heading 4</code></p>

标签: javascriptnode.jsarraysloopsfor-loop

解决方案


您可以创建一个数组来跟踪每个标题级别的第一次运行。如果不是第一次运行,则重置所有以下级别。

const header = [10, 20, 30, 40, 50, 60],
      contentHeaders = document.querySelectorAll(
        'h1, h2, h3, h4, h5, h6'
      ),
      startingNumbers   = [ 0,             // null
                            header[0] - 1, // h1
                            header[1] - 1, // h2
                            header[2] - 1, // h3
                            header[3] - 1, // h4
                            header[4] - 1, // h5
                            header[5] - 1, // h6
                          ];
// track the first run                      
let first_run = [true, true, true, true, true, true, true];

for( var item in contentHeaders ) {

  // this element from item number
  var element = contentHeaders[item],
      numberText = '';

  // limit the heading tag number in search
  const headingRegex = new RegExp('^H([1-6])$');

  // does the element match a heading regex
  if( !element || !element.tagName || !element.tagName.match( headingRegex ) ) {
        // return to beginning of loop
        continue;
  }

  // return the heading level number
  var elementLevel = RegExp.$1;

  // increment by 1
  startingNumbers[elementLevel]++;
  
  // reset all level below except for the first run
  if (!first_run[elementLevel]) resetBelowLevels(elementLevel);
  first_run[elementLevel] = false;
      
  // loop through the headings
  for( var levelNumber = 1; levelNumber <= 6; levelNumber++ ) {
        // if the number is lt the element number
        if( levelNumber <= elementLevel ) {
          numberText += startingNumbers[levelNumber] + ".";
        }
  }

  element.innerHTML =  numberText + ' ' + element.innerText;

}

function resetBelowLevels(current_level) {
  // current_level is string so need to convert it to number
  for(let i = +current_level + 1; i <= 6; i++) {
    startingNumbers[i] = 0;
  }
}
* { font-family: monospace; font-size: 16px !important; }
<h1>Heading 1</h1>
<p>I should be <code>10. Heading 1</code></p>
<h2>Heading 2</h2>
<p>I should be <code>10.20. Heading 2</code></p>
<h3>Heading 3</h3>
<p>I should be <code>10.20.30. Heading 3</code></p>
<h4>Heading 4</h4>
<p>I should be <code>10.20.30.40. Heading 4</code></p>
<h5>Heading 5</h5>
<p>I should be <code>10.20.30.40.50. Heading 5</code></p>
<h6>Heading 6</h6>
<p>I should be <code>10.20.30.40.50.60. Heading 6</code></p>

<hr>

<h2>Heading 2</h2>
<p>I should be <code>10.21. Heading 2</code></p>
<h3>Heading 3</h3>
<p>I should be <code>10.21.1 Heading 3</code></p>

<hr>

<h2>Heading 2</h2>
<p>I should be <code>10.22. Heading 2</code></p>
<h3>Heading 3</h3>
<p>I should be <code>10.22.1. Heading 3</code></p>
<h4>Heading 4</h4>
<p>I should be <code>10.22.1.1. Heading 4</code></p>


推荐阅读