Подборка задач и решении по курсу JS: API DOM

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


Рекурсивный поиск тегов

Напишите функцию поиска recSearchTags, которая принимает на вход document и имя тега, а возвращает массив из всех элементов соответствующих этому тегу. Поиск идет в теге body

// <body>
//   <p>1</p>
//   text
//   <div><p>2</p></div>
// </body>
const elements = recSearchTags(document, 'p');
// ['<p>1</p>' '<p>2</p>'] где каждый элемент это объект соответствующего типа
console.log(elements.length); // 2

По сути это реализация коробочного метода js dom api — getElementsByTagName:

(function () {
    window.recSearchTags = function (d, t) {
        var buffer = [],
            rec = function (buffer, target, t) {
                for (var i = 0; i < target.children.length; i++) {
                    var el = target.children[i];
                    if (buffer.indexOf(el) !== -1)
                        break;
                    if (el.tagName === t.toUpperCase())
                        buffer.push(el);
                    if (el.hasChildNodes())
                        rec(buffer, el, t);
                }
            };
        for (var i = 0; i < d.body.children.length; i++)
            rec(buffer, d.body, t);
        return buffer;
    }
})();

Функция идет с корня (в данном случае body) и рекурсивно обрабатывает все узлы DOM, при этом сравнивая передаваемое значение искомого тега с последовательно обрабатываемыми в цикле элементами (el.tagName === t.toUpperCase()), записывая при совпадении элемент в массив. Если узел имеет дочерние элементы рекурсивно начинает обрабатывать их точно таким же образом, пока не упрётся в «листовой» (не узловой) элемент.

Преобразование коллекции в массив

В примере выше написанная функция по умолчанию возвращает массив элементов, а это значит, что доступны методы для работы именно с массивами и возможно к примеру отсортировать их или сделать reverse. Но по умолчанию встроенный метод getElementsByTagName возвращает коллекцию элементов, а не массив (прототип HTMLCollection) и, следовательно там массивных методов уже нет. Но что, если бы нам хотелось поработать с коллекцией, но в контексте массива? Тогда нам нужно сделать преобразование, например вот такое:

(function () {
    window.transformToArray = function (selector) {
        var buf = [];
        [].forEach.call(selector, function (el) {
            buf.push(el);
        });
        return buf;
    }
})();

Потом выбираем элементы, например:

transformToArray(document.getElementsByTagName('input'));   //   __proto__ :Array

Нахождение и оборачивание текста в тег

Реализуйте функцию prettify, которая находит текст (дочерние текстовые ноды) внутри элемента div и оборачивает текст в параграф

// <body>
//   <p>Boom</p>
//   text
//   <div>Bam</div>
// </body>
const elements = prettify(document);
console.log(document.body.innerHTML);
// <body>
//   <p>Boom</p>
//   text
//   <div><p>Bam</p></div>
// </body>

Про обход элементов можно прочитать здесь: https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker

(function () {
    window.prettify = function (d) {
        var treeWalker = document.createTreeWalker(
            /*
             * https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker
             * */
            d,                              //  Root element  (example: DOCUMENT)
            4                               //  Shows Text nodes
            ),
            elementsArray = [],
            valuesArray = [];
        while (treeWalker.nextNode()) {
            var parentEl = treeWalker.currentNode.parentNode,
                valueElement = treeWalker.currentNode.nodeValue.trim();
            if (parentEl.tagName === 'DIV' && valueElement !== "") {
                elementsArray.push(parentEl);
                valuesArray.push(valueElement);
            }
        }
        for (var i = 0; i < elementsArray.length; i++) {
            elementsArray[i].innerHTML = '<p>' + valuesArray[i] + '</p>';
        }
    };
})();
window.onload = function () {
        const elements = prettify(document);
        console.log(document.body.innerHTML);
    }

Поиск и нормализация имён классов

Реализуйте функцию normalize, которая нормализует имена классов для всех элементов на странице. В данном случае это означает что происходит преобразование всех классов написанных используя kebab нотацию в camelCase нотацию: text-center => textCenter

// <body>
//   <div class="text-center row-b">Bam</div>
// </body>
const elements = normalize(document);
console.log(document.body.innerHTML);
// <body>
//   <div class="textCenter rowB">Bam</div>
// </body>

(function () {
    window.normalize = function (d) {
        var all = d.body.getElementsByTagName('*'),
            pattern = /.*-.*/;
        for (var i = 0; i < all.length; i++) {
            var res = '';
            //all[i].className;               => строка класса для элемента
            //all[i].classList;               => список классов в виде массива
            for (var j = 0; j < all[i].classList.length; j++) {
                var str = all[i].classList[j],
                    pos = str.indexOf('-');
                if (pattern.test(str)) {
                    var chunkStr = str.split(''),
                        resultStr = '',
                        newChar = chunkStr[pos + 1].toUpperCase();
                    chunkStr.splice(pos, 1);
                    chunkStr[pos] = newChar;
                    resultStr = chunkStr.join('');
                } else {
                    resultStr = str;
                }
                res += resultStr + ' ';
            }
            if (res !== '') {
                all[i].removeAttribute('class');
                all[i].setAttribute('class', res.trim());
            }
        }
    };
    window.onload = function () {
        const elements = normalize(document);
        console.log(document.body.innerHTML);
    }
})();


Похожие заметки:

Скрипт динамической ширины

Скрипт для равномерного распределения блоков по ширине родительского контейнера. В качестве контейнера может выступать любой блок как определенной ширины, так и неопределенной, вплоть до body. Что умеет?

  • Нарезать блоки на одинаковую ширину в зависимости от заданного количества колонок
  • Генерировать нужное количество колонок
  • Проставлять clearfix после оканчивающей ряд колонки, чтобы вовремя отменить обтекание
  • Удалять лишние clearfix

Открыть здесь

Удобная разработка с livereload, установка browser-sync

Livereload — «живая» перезагрузка страниц в браузере, при изменении в файлах проекта. Обычно очень удобно при разработке нового проекта, когда постоянно вносятся и тестируются изменения, особенно если дебажим во многих вкладках и браузерах сразу

Открыть здесь

Верстка

Услуги » верстка страниц сайта

Открыть здесь


Перед тем как писать комментарии, рекомендую ознакомиться:

Markdown синтаксис »

Оформление кода »

Нужна аватарка »

Комментарии