首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >有什么好的代码可以从JavaScript中的HTML元素中生成TOC?

有什么好的代码可以从JavaScript中的HTML元素中生成TOC?
EN

Stack Overflow用户
提问于 2011-04-28 13:58:19
回答 3查看 2.9K关注 0票数 3

我想在JavaScript中生成如下所示的TOC:

代码语言:javascript
复制
<ol>
  <li>Heading 1</li>
  <li>Heading 2
    <ol>
      <li>Heading 2-1</li>
      <li>Heading 2-2</li>
    </ol>
  </li>
  <li>Heading 3</li>
</ol>

以及生成上述TOC的HTML代码:

代码语言:javascript
复制
<section id="toc">
  <p>This will be replaced with generated TOC.
</section>

<article>
  <h1>Heading 1<h1>
  <p>Bla bla bla.</p>

  <h1>Heading 2<h1>
  <p>Bla bla bla.</p>

    <h2>Heading 2-1<h2>
    <p>Bla bla bla.</p>

    <h2>Heading 2-2<h2>
    <p>Bla bla bla.</p>

  <h1>Heading 3<h1>
  <p>Bla bla bla.</p>
</article>

我真的被困住了:(您如何编写代码来生成TOC?我喜欢jQuery还是纯JavaScript。

更新

这对我来说很难,但不知何故,我想我已经做到了:

代码语言:javascript
复制
  $(function () {
    var assigned_level = 0,
        current_level = 0,
        id_number = 1,
        parent_node = "article",
        toc_html = '';

    $(parent_node + " *").each(function () {
      if (this.nodeName.length === 2 && this.nodeName.charAt(0) === "H") {
        $(this).attr("class", "heading");
      }
    });

    $(".heading").each( function () {
      current_level = this.nodeName.charAt(1);

      $(this).attr('id', "toc-" + id_number);

      // Close a list if a same level list follows.
      if (assigned_level !== current_level - 1) {
        toc_html += "</li>"
      }

      // Open parent lists if a child list follows.
      while (assigned_level < current_level) {
        toc_html += "<ol>";
        assigned_level += 1;
      }

      // Close child lists and the parent list if
      // the same level parent list follows.
      while (assigned_level > current_level) {
        toc_html += "</ol></li>";
        assigned_level -= 1;
      }

      toc_html += 
        '<li><a href="#' + this.id + '">' + $(this).html() + "</a>";
      id_number += 1;
    });

    // Close everything
    while (assigned_level > 0) {
      toc_html += "</li></ol>";
      assigned_level -= 1;
    }

    $("#toc").html(toc_html);
  });

我仍然不明白我做了什么:P,也许还有更复杂的方法。请指出你发现的任何东西。

谢谢。

EN

回答 3

Stack Overflow用户

发布于 2011-04-28 14:14:12

首先,您需要关闭h1,h2标记=)

如果您执行$("h1, h2, h3, h4, h5, h6"),您将得到与文档中显示的标记顺序相同的标记。所以你可以在这个数组上做一个循环并检查级别。如果最后一个标记是H1,并且您找到了一个H2,这意味着您需要创建一个<ol>。另一方面,如果您有一个H3,而下一个是H2,这意味着您需要关闭<ol>

最困难的部分是最终关闭剩余的<ol>

希望这能有所帮助。

票数 4
EN

Stack Overflow用户

发布于 2011-04-28 14:13:59

在我们看到你到目前为止想出的东西之前,我不想太深入。

然而,看看.each() .children().find()。这些应该给你一些关于如何完成你想要做的事情的想法。

票数 1
EN

Stack Overflow用户

发布于 2020-01-31 14:53:02

我知道这个问题已经8岁了,但我有个建议。也许不是最有效的方法,也不是最短的,但它是有效的。

  • 首先,我得到了所有标题的数组。
  • 然后,通过添加每个标题的级别、id和父级来准备该数组。
  • 然后,我将该数组转换为递归的、分层的数组。
  • 然后生成HTML有序列表。
  • 然后将列表添加到TOC中。

在页面末尾,添加以下JavaScript:

代码语言:javascript
复制
// prepare the array by adding level, ID and parent to each item of the array
function prepare( array ) {
    let idt, level, t;
    for( let i = 0, n = array.length; i < n; i++ ) {
        t       = array[ i ];
        t.el    = t;
        level   = parseInt( t.tagName[1], 10 );
        t.level = level;
        t.idt   = i + 1;

        if( level <= 1 ) t.parent = 0;
        if( i ) {
            if( array[ i - 1 ].level < level ) {
                t.parent = array[ i - 1 ].idt;
            } else if( array[ i - 1 ].level == level ) {
                t.parent = array[ i - 1 ].parent;
            } else {
                for( let j = i - 1; j >= 0; j-- ) {
                    if( array[ j ].level == level - 1) {
                        t.parent = array[ j ].idt;
                        break;
                    }
                }
            }
        }
    }
    return array;
}

// transform a flat array in a hierarchical array
function hierarchical( items ) {
    let hashTable = Object.create( null );
    items.forEach( item => hashTable[ item.idt ] = { ...item, subitems : [] } );
    let tree = [];
    items.forEach( item => {
        if( item.parent )
            hashTable[ item.parent ].subitems.push( hashTable[ item.idt ] );
        else
            tree.push(hashTable[ item.idt ]);
    });
    return tree;
}

// return an UL containing each title in a LI and possibly other items in UL sub-lists.
function add_list( titles ) {
    let li, a, anchor;
    let ol = document.createElement( "ol" );
    if( titles && titles.length ) {
        for( t of titles ) {
            if( t.el.id ) anchor = t.el.id;
            else anchor = t.el.textContent;
            if( ! anchor ) anchor = "inconnu";
            anchor = anchor.replace( /\W/g, "" );
            t.el.id = anchor;
            li = document.createElement( "li" );
            a  = document.createElement( "a"  );
            a.href = `#${anchor}`;
            a.innerHTML = t.el.textContent;
            li.append( a );
            if( t.subitems && t.subitems.length ) {
                li.append( add_list( t.subitems ) );
            }
            ol.append( li );
        }
    }
    return ol;
}

//get the toc element
let divtoc = document.getElementById( "toc" );

// get the article element
let article  = document.getElementById( "article"  );
if( toc && article ) {
    let titles = article.querySelectorAll( "h1, h2, h3, h4, h5, h6" );
    titles = prepare( titles );
    titles = hierarchical( titles );
    let ol_racine = add_list( titles );
    toc.append( ol_racine );
}

您将得到预期的结果:

代码语言:javascript
复制
<section id="toc">
    <ol>
        <li><a href="#Heading1">Heading 1</a></li>
        <li>
            <a href="#Heading2">Heading 2</a>
            <ol>
                <li><a href="#Heading21">Heading 2-1</a></li>
                <li><a href="#Heading22">Heading 2-2</a></li>
            </ol>
        </li>
        <li><a href="#Heading3">Heading 3</a></li>
    </ol>
</section>
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5819807

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档