Создать иерархию заголовков в виде упорядоченного списка - PullRequest
6 голосов
/ 31 января 2009

Я размышлял об этом некоторое время, но не могу найти рабочее решение. Я даже не могу написать это псевдо ...

Скажем, например, у вас есть страница с такой структурой заголовка:

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

Каждый раз, когда я пытаюсь начать с определенной методологии, она становится очень раздутой.

Решение должно пройти через каждый заголовок и поместить его в соответствующий вложенный список - я повторяю это себе, но ничего не могу набросать!

Даже если у вас в голове есть методология, но у вас нет времени ее кодировать, я все равно хотел бы это знать! :)

Спасибо!

Ответы [ 4 ]

3 голосов
/ 31 января 2009

Проблема здесь в том, что нет хорошего способа получить заголовки в порядке документа. Например, вызов jQuery $('h1,h2,h3,h4,h5,h6') вернет все ваши заголовки, но сначала будут все <h1> с, затем <h2> и т. Д. При использовании селекторов с разделителями-запятыми никакая основная рама пока не возвращает элементы в порядке документа.

Вы можете решить эту проблему, добавив общий класс к каждому заголовку. Например:

<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 теперь должно быть вашим <ol>.

Также обратите внимание, что при этом будет обрабатываться <h4>, за которым следует <h1> (перемещение более чем на один уровень вниз одновременно), но он не будет обрабатывать <h1> с последующим <h4> (более одного уровень вверх за один раз).

2 голосов
/ 31 января 2009

Сначала постройте дерево. Псевдокод (потому что я не владею 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; 
}

Наконец, вставьте LI, возвращаемый buildList в UL для каждого treeRoots.

В jQuery вы можете получать элементы заголовка в следующем порядке:

var headers = $('*').filter(function() {
    return this.tagName.match(/h\d/i);
}).get();
1 голос
/ 13 февраля 2016

Я могу представить себе множество ситуаций, когда вы, возможно, думаете об этом. Во многих ситуациях вам действительно понадобится только внешний вид иерархии, а не сама регенерированная иерархия 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 '; }

1006 *

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>';
}
0 голосов
/ 23 февраля 2016

Это выберет все теги h1-h6 в разделе DOM документа docElTgt и будет учитывать заголовок заказа в документе html

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

примеры значения, которое может быть docElTgt:

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

После выбора всех заголовков можно будет применить алгоритм для создания иерархии в виде упорядоченного списка, как показано другими пользователями

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...