繁体   English   中英

递归JS函数列出Hx HTML标签?

[英]Recursive JS Function to List Hx HTML tags?

我有一些代码:

$('section').each(function() {
    var the_id;
    var list_item;
    $(this).find('h2').each(function() {
        the_id = $(this).attr('id');
        $('nav > ol').append('<li><a href="#' + the_id + '">' + $(this).text() + '</a></li>');
        $(this).siblings('h3').each(function(i) {
            the_id = $(this).attr('id');
            if (i == 0) {
                $('nav > ol > li:last').append('<ol></ol>');
            }
            $('nav > ol > li:last > ol').append('<li><a href="#' + the_id + '">' + $(this).text() + '</a></li>');
        });
    });
});

它生成一些HTML,如:

<li>
   <a href="#example-1">Example 1</a>
   <ol>
      <li>
         <a href="#example-1a">Example 1a</a>
     </li>
     <li>
         <a href="#example-1b">Example 1b</a>
     </li>
   </ol>
</li>
<li>
   <a href="#another-example">Another Example</a>
</li>
<li>
  <a href="#last-one">Last One</a>
</li>
<li>
   <a href="#just-kidding--another">Just kidding, another</a>
   <ol>
      <li>
         <a href="#this-is-a-sub-header">This is a sub header</a>
      </li>
   </ol>
</li>

我的问题是,我的JS只能写到它(h2,然后查找h3s,我必须编写另一个回调来做h4然后另一个用于h5和h6。我怎么能写一个递归函数呢?这个?

如何构建HTML列表呢? 我真的很喜欢写/理解递归代码。 迭代通常对我来说更容易。

function buildToc(container) {
    var html = "", lastLevel = -1;
    container.find('h1, h2, h3, h4, h5, h6, h7, h8, h9').each(function() {
        var $this = $(this);
        var level = this.tagName.match(/H(\d)/)[1];
        if (lastLevel < level) {
            html += "<ol>";
        }
        if (lastLevel > level)  {
            html += "</ol>";
        }
        html += "<li><a href='"+ this.id + "' >" + $this.text() + "</a></li>";
        lastLevel = level;
    });
    return html;
}
$('nav').append( buildToc( $('article section') ) );

我在你的页面上运行它,它复制了你现有的TOC。 并且您不需要每个级别的自定义代码; 又脏又脏。

有点盯着这个,我想我想出了你想要的东西。 每个级别实际上并没有不同,你刚刚解释了所有级别的最低级别。 就像Matt的评论所说,你需要单独声明回调。 但是您还需要将当前级别的列表传递给它,这样您就可以将其附加到正确的位置。 我们可以尝试一种使用方法来构造回调的方法,如下所示:

function Generator(e, level) {
    var list = e; // I think you need this for the closure to work, but my js is rusty so I may be wrong.

    return function() {
        var new_list = $('<ol></ol>');
        list.append(new_list); // you might want to make sure there's more than 0 siblings?

        $(this).siblings('h' + level).each(function(i) {
            the_id = $(this).attr('id');
            new_list.append('<li><a href="#' + the_id + '">' + $(this).text() + '</a></li>');
            if (level < 6) { // your max h tag level
                Generator(new_list, level + 1)();
            }
        });
    }
}

我不确定我是否实现了你正在尝试正确执行的操作,但我的想法是你可以继续创建子列表并以递归方式将它们传递回函数。 您最初的一个问题是每次都必须让jQuery选择器更深入。 这种方法解决了这个问题。 你简单地称它为:

$('section').each(Generator($('nav'), 2)); // maybe not nav, something close to that

显然你的代码开始时使用$(this).find('h2')而不是$(this).siblings('h2') ,因此需要在该区域进行一些调整。 但我相信这不是什么大不了的事。

我没有测试过这个,所以我可能在某个地方至少犯了一个错误。

谷歌快速搜索显示了这个脚本 ; 它很简单,但你应该能够根据自己的需要进行调整(或者只是借用这个想法并编写自己的代码)。

在玩了一些之后,我认为Juan是对的:迭代方法似乎更容易。 我整理了一个使用类似方法的快速jQuery插件:

(function($) {
    $.fn.buildTOC = function(options) {
        var opts = $.extend({
                scan: $(document) // By default, search the entire page for headings
            }, options),
            $toc = $(this),       // This is where we'll place our TOC links

            /*
            * Get the current level from the Heading tag.
            */
            getLevel = function(h) {
                return parseInt(h.substring(1));
            },

            /*
             * Creates a new sublist and returns it.
             * The randomly-generated ID just makes it easier to find the new list.
             */
            pushLevel = function(toc) {
                var id = 'node' + Math.round(Math.random() * 50000 + 1);
                toc.append($('<ol id="' + id + '"></ol>'));
                return $('#' + id, toc);
            },

            /*
             * Returns the last sublist containing an element at the current level;
             * otherwise, returns the parent list (for top-level items).
             */
            popLevel = function(toc, level) {
                var sub = $('.toc-level-' + level + ':last', toc);
                if (sub.length) {
                    return sub.parent();
                } else {
                    return $toc.children('ol');
                }
            },

            /*
             * Appends a link for the current tag to the current list.
             * Also adds a class for the current level (handy for styling), so it's easy
             * to find items at this level.
             */
            appendLink = function(toc, tag, level) {
                toc.append($('<li class="toc-level-' + level + '"><a href="#' + tag.id + '">' + tag.innerHTML + '</a></li>'))
            },

            buildTOC = function(toc) {
                var headings = $('h1,h2,h3,h4,h5,h6', opts.scan),
                    lastLevel = 0;
                for (var i=0, len=headings.length; i<len; i++) {
                    var currTag = headings[i],
                        currLevel = getLevel(currTag.tagName);
                    if (lastLevel == currLevel) {
                        // Siblings: just add a link for this item
                        appendLink(toc, currTag, currLevel);
                    } else if (lastLevel < currLevel) {
                        // Child: create a new list and append to that
                        toc = pushLevel(toc);
                        appendLink(toc, currTag, currLevel);
                    } else {
                        // Parent: move back out to the appropriate list
                        toc = popLevel(toc, currLevel);
                        appendLink(toc, currTag, currLevel);
                    }
                    lastLevel = currLevel;
                }
            };

        buildTOC($toc);
    };
})(jQuery);

你会这样使用它:

$(function() {
    $('#toc').buildTOC();
})

其中toc是链接应该到达的容器的ID。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM