生成标题层次结构作为有序列表

Jam*_*mes 6 html javascript methodology

我一直在思考这个问题,但无法提出一个有效的解决方案.我甚至不能伪造它...

比如说,你有一个页面,其标题结构如下:

<h1>Heading level 1</h1>

    <h2>Sub heading #1</h2>

    <h2>Sub heading #2</h2>

        <h3>Sub Sub heading</h3>

    <h2>Sub heading #3</h2>

        <h3>Sub Sub heading #1</h3>

        <h3>Sub Sub heading #2</h3>

            <h4>Sub Sub Sub heading</h4>

    <h2>Sub heading #4</h2>

        <h3>Sub Sub heading</h3>
Run Code Online (Sandbox Code Playgroud)

使用JavaScript(任何框架都没问题),您将如何生成这样的列表:(使用嵌套列表)

<ol>
    <li>Heading level 1
        <ol>
            <li>Sub heading #1</li>
            <li>Sub heading #2
                <ol>
                    <li>Sub Sub heading</li>
                </ol>
            </li>
            <li>Sub heading #3
                <ol>
                    <li>Sub Sub heading #1</li>
                    <li>Sub Sub heading #2
                        <ol>
                            <li>Sub Sub Sub heading (h4)</li>
                        </ol>
                    </li>
                </ol>
            </li>
            <li>Sub heading #4
                <ol>
                    <li>Sub Sub heading</li>
                </ol>
            </li>
        </ol>
    </li>
</ol>
Run Code Online (Sandbox Code Playgroud)

每当我尝试以某种方法开始时,它最终变得非常臃肿.

解决方案需要遍历每个标题并将其放入适当的嵌套列表中 - 我不断重复这一点,但我不能勾勒出任何东西!

即使你的头脑中有一种方法,但没有时间对其进行编码,我仍然想知道它!:)

谢谢!

Pre*_*aul 5

这里的问题是没有任何好的方法来按文档顺序检索标题。例如,jQuery 调用$('h1,h2,h3,h4,h5,h6')将返回所有标题,但所有<h1>s 将首先出现<h2>,然后是 s,依此类推。当您使用逗号分隔选择器时,还没有主要框架按文档顺序返回元素。

您可以通过向每个标题添加一个公共类来解决这个问题。例如:

<h1 class="heading">Heading level 1</h1>

    <h2 class="heading">Sub heading #1</h2>

    <h2 class="heading">Sub heading #2</h2>

        <h3 class="heading">Sub Sub heading</h3>

    <h2 class="heading">Sub heading #3</h2>

    ...
Run Code Online (Sandbox Code Playgroud)

现在选择器$('.heading')会将它们全部按顺序排列。

下面是我用 jQuery 实现的方法:

var $result = $('<div/>');
var curDepth = 0;

$('h1,h2,h3,h4,h5,h6').addClass('heading');
$('.heading').each(function() {

    var $li = $('<li/>').text($(this).text());

    var depth = parseInt(this.tagName.substring(1));

    if(depth > curDepth) { // going deeper

        $result.append($('<ol/>').append($li));
        $result = $li;

    } else if (depth < curDepth) { // going shallower

        $result.parents('ol:eq(' + (curDepth - depth - 1) + ')').append($li);
        $result = $li;

    } else { // same level

        $result.parent().append($li);
        $result = $li;

    }

    curDepth = depth;

});

$result = $result.parents('ol:last');

// clean up
$('h1,h2,h3,h4,h5,h6').removeClass('heading');
Run Code Online (Sandbox Code Playgroud)

$result现在应该是你的了<ol>

另请注意,这将处理 an<h4>后跟一个<h1>(一次向下移动不止一级),但不会处理 an<h1>后跟一个<h4>(一次向上移动超过一级)。


str*_*ger 3

首先,建一棵树。伪代码(因为我不熟悉Javascript):

var headings = array(...);
var treeLevels = array();
var treeRoots = array();

foreach(headings as heading) {
    if(heading.level == treeLevels.length) {
        /* Adjacent siblings. */

        if(heading.level == 1) {
            treeRoots[] = heading;  // Append.
        } else {
            treeLevels[treeLevels.length - 2].children[] = heading;  // Add child to parent element.
        }

        treeLevels[treeLevels.length - 1] = heading;
    } else if(heading.level > treeLevels.length) {
        /* Child. */

        while(heading.level - 1 > treeLevels.length) {
            /* Create dummy headings if needed. */
            treeLevels[] = new Heading();
        }

        treeLevels[] = heading;
    } else {
        /* Child of ancestor. */

        treeLevels.remove(heading.level, treeLevels.length - 1);

        treeLevels[treeLevels.length - 1].children[] = heading;
        treeLevels[] = heading;
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,我们横穿它,构建列表。

function buildList(root) {
    var li = new LI(root.text);

    if(root.children.length) {
        var subUl = new UL();
        li.children[] = subUl;

        foreach(root.children as child) {
            subUl.children[] = buildList(child);
        }
    }

    return li; 
}
Run Code Online (Sandbox Code Playgroud)

最后,将LI返回的 by插入buildListULforeach中treeRoots

在 jQuery 中,您可以按如下顺序获取标题元素:

var headers = $('*').filter(function() {
    return this.tagName.match(/h\d/i);
}).get();
Run Code Online (Sandbox Code Playgroud)