Pergunta

Eu estive pensando isso por um tempo, mas não pode vir até com uma solução de trabalho. Eu não posso nem pseudo código ...

Digamos, por exemplo, você tem uma página com uma estrutura título como este:

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

Usando JavaScript (qualquer quadro é bom), como é que você vai fazer sobre a produção de uma lista como esta: (com listas aninhadas)

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

Toda vez que tento e começar com uma determinada metodologia acaba ficando muito inchado.

A solução precisa para atravessar cada título e colocá-lo em sua lista aninhada apropriado - eu ficar repetindo isso para mim, mas não posso esboçar qualquer coisa!

Mesmo se você tem uma metodologia em sua cabeça, mas não tenho tempo para o código-lo eu ainda gostaria de conhecê-lo! :)

Obrigado!

Foi útil?

Solução

Em primeiro lugar, construir uma árvore. Pseudocódigo (porque eu não sou fluente em 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;
    }
}

Em seguida, transversal ele, a construção da lista.

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

Finalmente, inserir o LI retornado por buildList num UL para cada treeRoots.

Em jQuery, você pode buscar elementos de cabeçalho, a fim como tal:

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

Outras dicas

O problema aqui é que não há nenhuma boa maneira de recuperar os títulos na ordem do documento. Por exemplo, a chamada $('h1,h2,h3,h4,h5,h6') jQuery irá retornar todos os seus títulos, mas todos <h1>s virá primeiro, seguido pelos <h2>s, e assim por diante. Sem grandes ainda trabalho Frame Retorna elementos na ordem do documento quando você usar a vírgula delimitado seletores.

Você pode superar este problema adicionando uma classe comum a cada título. Por exemplo:

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

    ...

Agora, o $('.heading') selector vai levá-los todos em ordem.

Aqui está como eu faria isso com 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 agora deve ser o seu <ol>.

Além disso, nota que esta irá lidar com uma <h4> seguido por um <h1> (movendo mais de um nível baixo de uma vez), mas não vai lidar com um <h1> seguido por um <h4> (mais de um nível acima de cada vez).

Eu posso imaginar muitas situações em que você pode ser cismar isso. Para muitas situações, você realmente só precisa a aparência da hierarquia, e não a hierarquia HTML regenerada propriamente dito, para o qual você pode fazer algo simples como este:

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

Isso irá selecionar todas as tags h1-h6 para a seção docElTgt DOM do documento e será respeitado o título ordem estão no documento html

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

exemplos do valor que pode ser docElTgt:

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

Depois de selecionado todos título será possível aplicar algoritmo para fazer hierarquia como lista ordenada como mostrou por outros usuários

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top