【问题标题】:Produce heading hierarchy as ordered list将标题层次结构生成为有序列表
【发布时间】:2009-01-30 21:58:00
【问题描述】:

我一直在思考这个问题,但无法提出可行的解决方案。我什至无法对其进行伪编码...

例如,假设您有一个标题结构如下的页面:

<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>

使用 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>

每次我尝试从某种方法开始时,它都会变得非常臃肿。

解决方案需要遍历每个标题并将其放入相应的嵌套列表中——我不断对自己重复这一点,但我无法勾勒出任何东西!

即使您脑子里有一套方法,但没有时间编写代码,我仍然想知道它! :)

谢谢!

【问题讨论】:

  • @JimmyP:标题之间有内容吗?该内容是否需要存在于最终结构中?
  • 老话题,但是在jQuery(1.10.2)的当前实现中,$('h1, ... , h6')会按照标签在页面上出现的顺序返回。

标签: javascript html methodology


【解决方案1】:

这里的问题是没有任何好的方法可以按文档顺序检索标题。例如,jQuery 调用 $('h1,h2,h3,h4,h5,h6') 将返回所有标题,但所有 &lt;h1&gt;s 将首先出现,然后是 &lt;h2&gt;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>

    ...

现在选择器$('.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');

$result 现在应该是您的&lt;ol&gt;

另外,请注意,这将处理 &lt;h4&gt; 后跟 &lt;h1&gt; (一次向下移动多个级别),但它不会处理 &lt;h1&gt; 后跟 &lt;h4&gt; (多个一次升级)。

【讨论】:

  • 注意:$result.parents('li:eq ... 应该是 $result.parents('ol:eq ...,因为我们附加到有序列表而不是列表项。
  • 这是一个很棒且非常完整的解决方案。谢谢!
  • 不应该只有'ol:eq(' + (curDepth - depth) + ')'吗?
【解决方案2】:

首先,构建一棵树。伪代码(因为我不精通 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;
    }
}

接下来,我们遍历它,构建列表。

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

最后,将buildList 返回的LI 插入每个treeRootsUL

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

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

【讨论】:

  • 这里的问题是没有任何好的方法可以按文档顺序检索标题。例如,jQuery 调用 $('h1,h2,h3,h4,h5,h6') 将返回所有标题,但所有

    将首先出现,然后是

    ,依此类推。尚无主要框架返回文档顺序。

  • @Prestaul,我添加了一个 jQuery sn-p 来展示你将如何做到这一点。感谢您提及。
  • @strager,这是一个很好的解决方法。我刚刚发布了一个解决方案(使用 jQuery)通过首先向标题添加一个公共类来获取列表: $('h1,h2,h3,h4,h5,h6').addClass('heading'); var $aiches = $('.heading');
【解决方案3】:

我可以设想很多情况,您可能会过度考虑这一点。在许多情况下,您实际上只需要层次结构的 外观,而不需要实际重新生成的 HTML 层次结构本身,您可以为此做一些简单的事情:

#nav li.h1 { padding: 0 0 0  0px; } #nav li.h1:before { content: 'h1 '; }
#nav li.h2 { padding: 0 0 0 10px; } #nav li.h2:before { content: 'h2 '; }
#nav li.h3 { padding: 0 0 0 20px; } #nav li.h3:before { content: 'h3 '; }
#nav li.h4 { padding: 0 0 0 30px; } #nav li.h4:before { content: 'h4 '; }
#nav li.h5 { padding: 0 0 0 40px; } #nav li.h5:before { content: 'h5 '; }
#nav li.h6 { padding: 0 0 0 50px; } #nav li.h6:before { content: 'h6 '; }

 

for (i=1; i<=6; i++) {
    var headers = document.getElementsByTagName('h'+i);
    for (j=0; j<headers.length; j++) {
        headers[j].className = 'h';
    }
}
var headers = document.getElementsByClassName('h');
var h1 = document.getElementsByTagName('h1')[0];
h1.parentNode.insertBefore(document.createElement('ul'),h1.nextSibling);
h1.nextSibling.id = 'nav';
for (i=0; i<headers.length; i++) {
    document.getElementById('nav').innerHTML += '<li class="'+headers[i].tagName.toLowerCase()+'">'+headers[i].innerHTML+'</li>';
}

【讨论】:

    【解决方案4】:

    这会将所有 h1-h6 标记选择到文档的 docElTgt DOM 部分,并且将遵循顺序标题进入 html 文档

    var hItemsList = docElTgt.querySelectorAll('h1, h2, h3, h4, h5, h6');
    

    可以是docElTgt的值示例:

    docElTgt = document.body;
    docElTgt = anyelement.id;
    

    选择所有标题后,可以应用算法将层次结构作为其他用户显示的有序列表

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多