ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Category:

HTML-дерево из объекта, итерации, innerHTML

Начало:
1. HTML-дерево из объекта, рекурсивный способ
2. HTML-дерево из объекта, итеративный способ
3. HTML-дерево из объекта, рекурсия, innerHTML

Последний (четвертый) вариант (который я хотел бы рассмотреть) решения задачи «Создайте дерево из объекта» к подразделу 1.7 «Изменение документа» второй части учебника по JavaScript.

Итак, тут я хочу решить обсуждаемую задачу итеративным способом, сконструировав строку с кодом на языке HTML и присвоив эту строку свойству innerHTML заданного контейнера container на HTML-странице с нашим скриптом на языке JavaScript. Такое решение с помощью рекурсии было продемонстрировано в прошлом посте.

В качестве базы я взял моё итеративное решение с созданием узлов через методы DOM и переписал его. Получилось следующее.
function createTree(container, tree) {
    if ( !container || !tree ) return;
    if ( Object.entries(tree).length == 0 ) return;
    
    let memory = [];            // память (стек) (в начале пуста)
    let cur_ent = [null, tree]; // текущая ссылка (в начале равна ссылке на корень дерева)
    let lastNodeVisited;        // последний обработанный узел на данный момент

    // цикл перебора узлов
    //     закончить цикл, как только память (стек) опустеет
    //     и текущая ссылка перестанет указывать на узел дерева
    while ( memory.length > 0 || cur_ent ) {

        // если текущая ссылка указывает на узел дерева, заглубляемся до листа
        // (итерация заглубления)
        if ( cur_ent ) {
            cur_ent.push( "" );     // создать ячейку-строку для хранения ul
            memory.push( cur_ent ); // поместить ссылку в память (стек)
                                    // перейти к левому потомку
            if ( Object.entries(cur_ent[1]).length > 0 ) {
                cur_ent = Object.entries(cur_ent[1])[0]; // потомок есть
            } else { cur_ent = null; }                   // потомка нет

        // если текущая ссылка не указывает на узел дерева (узел на предыдущей
        // итерации заглубления был листом или возвращаемся вверх)
        } else {
            let peekNode = memory[memory.length - 1]; // ссылка на узел в вершине стека

            // если узел на предыдущей итерации не был листом (возвращаемся вверх)
            if ( Object.entries(peekNode[1]).length > 0 ) {
                // ищем ветку, откуда вернулись
                let i;
                for (i = 0; i < Object.entries(peekNode[1]).length; i++) {
                    if ( Object.entries(peekNode[1])[i][1] == lastNodeVisited[1] ) break;
                }

                // если существует ветка правее, переходим по ней
                if ( i < Object.entries(peekNode[1]).length - 1 ) {
                    cur_ent = Object.entries(peekNode[1])[i + 1]; }
                // иначе (у узла на предыдущей итерации все потомки обработаны)
                else {
                                                    // ...обработка данных узла...
                                                    // помещаем li в вышестоящий ul
                    if (peekNode[0] && (memory.length - 2) >= 0) {
                        memory[memory.length - 2][2] +=
                            "<li>" + peekNode[0] + "<ul>" + peekNode[2] + "</ul></li>";
                    }
                    lastNodeVisited = memory.pop(); // убираем узел из памяти и запоминаем его
                }

            // если узел на предыдущей итерации был листом
            } else {
                                                // ...обработка данных узла...
                                                // помещаем li в вышестоящий ul
                if (peekNode[0] && (memory.length - 2) >= 0) {
                    memory[memory.length - 2][2] += "<li>" + peekNode[0] + "</li>";
                }
                lastNodeVisited = memory.pop(); // убираем узел из памяти и запоминаем его
            }
        }
    }
    container.innerHTML = "<ul>" + lastNodeVisited[2] + "</ul>"; // вставляем в контейнер
}

Синими комментариями я пометил те четыре места, в которые внёс изменения. В принципе, в данном случае работа с кодом на языке HTML как со строкой даже проще, чем работа с HTML-узлами с помощью методов DOM.

В общем, работа этого скрипта была подробно описана в соответствующем посте. Здесь я лишь заменил на месте третьего элемента массива cur_ent (текущий узел дерева) объект HTML-элемента ul на строку, содержащую код на языке HTML, который представляет тот же HTML-элемент ul.

Алгоритм проходит заданное дерево в обратном порядке (от листьев), конструируя нужную строку. Эта строка по мере продвижения наверх становится всё сложнее и в конце концов оказывается, что строка, хранящаяся при корневом узле дерева, содержит нужный код на языке HTML. Этот код остается лишь обернуть в самый верхний HTML-элемент ul, а затем вставить полученное в заданный контейнер container через его свойство innerHTML, что и требуется по условиям задачи.
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments