Рубрики
Без рубрики

Используя DOM, как профессионал

Как остановить бояться дома, используйте его в полной мере и на самом деле начать любить его. © Дэнни Моеркерке.

Автор оригинала: Danny Moerkerke.

фото Pankaj Patel на Несомненно

Когда я впервые начал работать профессиональным веб-разработчиком в 2008 году, я знал, что некоторые HTML, CSS и PHP. В то же время я также изучал эту вещь, называемую JavaScript, потому что он позволил мне показать и скрывать элементы и делать классные вещи, такие как раскрывающиеся меню.

В то время я работал для небольшой компании, которая в основном создала системы CMS для клиентов, и нам нужна несколько файлов загрузчик. То, что было невозможно в то время с родным JavaScript.

После некоторых поисков я нашел Необычное решение на основе вспышки И эта библиотека JavaScript под названием Mootools. Mootools имел этот крутой $ Функция для выбора элементов DOM и пришла с модулями, такими как прогрессы и запросы AJAX. Через несколько недель я обнаружил jQuery, и я был взорван.

Нет большего, неудовлетворяющегося манипуляции DOM, но легко, цепиливые селекторы, и он также пришел с целым кучей полезных плагинов.

Быстро вперед к 2019 год и мир правит рамочными рамками. Если вы начали в качестве веб-разработчика в последнее десятилетие, шансы заключаются в том, что вы едва ли воздействуете на «сырье» DOM, если когда-либо. Вам может даже не надо.

Несмотря на то, что рамки, такие как угловые и реагирующие, вызвали сильное снижение популярности jQuery, Он все еще используется ошеломляющим 66 миллионов сайтов который оценивается в Около 74% всех сайтов в мире Отказ

Наследие jQuery довольно впечатляет и отличный пример того, как он повлиял на стандарты Queryselector и QuerySelectorAll Методы, которые имитируют jQuery $ функция.

По иронии судьбы эти два метода были, вероятно, самая большая причина отклоненной популярности jQuery, поскольку они заменили самые используемые функциональные возможности jQuery: простой выбор элементов DOM.

Но родное DOM API является Verbose.

Я имею в виду, это $ против Document.QuerySelectorall Отказ

И это то, что выпускает разработчиков с использованием собственного API DOM. Но на это действительно нет необходимости в этом.

Наборная Дом API великолепен и невероятно полезен. Да, это Verbose, но это потому, что это низкоуровневые строительные блоки, предназначенные для создания абстракций. И если вы действительно беспокоитесь о дополнительных ключевых ударах: все современные редакторы и IDES обеспечивают превосходное завершение кода. Вы также можете псевдоним наиболее часто используемым функциональностью, как я покажу здесь.

Давайте прыгнем!

Выбор элементов

Один элемент

Чтобы выбрать один элемент, используя любое допустимое использование селектора CSS:

document.querySelector(/* your selector */)

Вы можете использовать любой селектор здесь:

document.querySelector('.foo')            // class selector
document.querySelector('#foo')            // id selector
document.querySelector('div')             // tag selector
document.querySelector('[name="foo"]')    // attribute selector
document.querySelector('div + p > span')  // you go girl!

Когда нет элементов, совпадающих, он вернет нулю.

Несколько элементов

Чтобы выбрать несколько элементов использования:

document.querySelectorAll('p')  // selects all 

elements

Вы можете использовать Document.QuerySelectorall так же, как Document.Queryselector Отказ Любой допустимый селектор CSS будет делать, и единственное отличие – Queryselector вернется один элемент, тогда как QuerySelectorAll вернет статический Odelist содержащий найденные элементы. Если нет обнаруженных элементов, это вернет пустой Odelist Отказ

А Odelist это намек, который похож на массив, но это не очень массив, поэтому у него нет тех же методов. Вы можете запустить foreach На нем, но не например карта , Уменьшить или Найти Отказ

Если вам нужно запускать методы массива на нем, вы можете просто превратить его в массив, используя разрушение или Array.rom :

const arr = [...document.querySelectorAll('p')];
// or
const arr = Array.from(document.querySelectorAll('p'));

arr.find(element => {...});  // .find() now works

Так что если бы вы сделаете getelementsbytagname ('p') и один

будет удален из документа, он будет удален из возвращенного Htmlcollection также.

Но если бы вы сделаете QuerySelectorAll ('p') и один

будет удален из документа, он все равно будет присутствовать в возвращении Odelist Отказ

Еще одно важное отличие состоит в том, что Htmlcollection может содержать только Htmlelements и а Odelist может содержать любой тип Узел Отказ

Относительные поиски

Вы не обязательно должны работать Queryselector (все) на документ. Вы можете запустить его на любом Htmlelement Чтобы запустить относительный поиск:

const div = document.querySelector('#container');
div.querySelectorAll('p')  // finds all 

tags in #container only

Но это все еще многословный!

Если вы все еще беспокоитесь о дополнительных нажатия клавиш, вы можете псевдоним оба метода:

const $ = document.querySelector.bind(document);
$('#container');const $$ = document.querySelectorAll.bind(document);
$$('p');

Там вы идете.

Идти вверх по дереву Дом

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

Но мы можем путешествовать по дереву Дом с ближайший () Способ, который также принимает любой действительный селектор CSS:

document.querySelector('p').closest('div');

Это найдет ближайший родитель

Элемент абзаца, выбранного Document.Queryselector ('p') Отказ Вы можете цепить эти звонки, чтобы идти дальше дерева:

document.querySelector('p').closest('div').closest('.content');

Добавление элементов

Код для добавления одного или нескольких элементов в дерево DOM печально известно для быстрого получения добросовестности. Допустим, вы хотите добавить следующую ссылку на вашу страницу:

Вам нужно будет сделать:

const link = document.createElement('a');
link.setAttribute('href', '/home');
link.className = 'active';
link.textContent = 'Home';document.body.appendChild(link);

Теперь представьте, что нужно сделать это на 10 элементов …

По крайней мере jQuery позволяет вам делать:

$('body').append('Home');

Хорошо угадай что? Есть родной эквивалент:

document.body.insertAdjacentHTML('beforeend', 'Home');

inslinadjacenthtml Метод позволяет вставлять произвольную допустимую HTML-строку в DOM на четырех положениях, указанных первым параметром:

'beforebegin': before the element
'afterbegin': inside the element before its first child
'beforeend': inside the element after its last child
'afterend': after the element

foo

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

Отказ Без inslinadjacenthtml Вы должны были бы сделать это:

const link = document.createElement('a');
const p = document.querySelector('p');p.parentNode.insertBefore(link, p);

Теперь вы можете просто сделать:

const p = document.querySelector('p');p.insertAdjacentHTML('beforebegin', '');

Существует также эквивалентный метод вставки элементов DOM:

const link = document.createElement('a');
const p = document.querySelector('p');p.insertAdjacentElement('beforebegin', link);

и текст:

p.insertAdjacentText('afterbegin', 'foo');

Движущиеся элементы

inslipadjacentelement Способ также может быть использован для перемещения вокруг существующих элементов в том же документе. Когда элемент, который вставлен с inslipadjacentelement Уже часть документа он просто будет перемещен.

Если у вас есть этот HTML:

Title

Subtitle

и

вставлен после

:

const h1 = document.querySelector('h1');
const h2 = document.querySelector('h2');h1.insertAdjacentElement('afterend', h2);

Это будет просто переехать, не скопировано:

Title

Subtitle

Замена элементов

Элемент DOM может быть заменен любым другим элементом DOM, используя его заменить погибший Метод:

someElement.replaceWith(otherElement);

Элемент заменен, может быть новый элемент, созданный с помощью Document.Createlement Или элемент, который уже является частью того же документа (в этом случае он снова будет перемещен, не скопирован):

Title

Subtitle

const h1 = document.querySelector('h1'); const h2 = document.querySelector('h2');h1.replaceWith(h2);// result:

Subtitle

Удаление элементов

Просто позвоните своему Удалить Метод:

const container = document.querySelector('#container');
container.remove();  // hasta la vista, baby

Намного лучше, чем старый путь:

const container = document.querySelector('#container');
container.parentNode.removeChild(container);

Создайте элемент из RAW HTML

inslinadjacenthtml Метод позволяет нам вставлять RAW HTML в документ, но что, если мы хотим создавать и элемент из RAW HTML и использовать его позже?

Мы можем использовать Domparser объект и его метод ParsefromString за это. Domparser Предоставляет возможность анализировать исходный код HTML или XML в документ DOM. Мы используем ParsefromString Способ создать документ только с одним элементом и возвращать только один элемент:

const createElement = domString => new DOMParser().parseFromString(domString, 'text/html').body.firstChild;
const a = createElement('Home');

Осмотрите домо

Стандартный API DOM также предоставляет некоторые удобные методы для проверки дома. Например, матчи Определяет, будет ли элемент соответствует определенному селектору:

Hello world

const p = document.querySelector('p'); p.matches('p'); // true p.matches('.foo'); // true p.matches('.bar'); // false, does not have class "bar"

Вы также можете проверить, является ли элемент ребенком другого элемента с Содержит Метод:

Foo

Bar

const container = document.querySelector('.container'); const h1 = document.querySelector('h1'); const h2 = document.querySelector('h2');container.contains(h1); // true container.contains(h2); // false

Вы можете получить еще более подробную информацию о элементах с по сравнению со днями метод. Этот метод позволяет определить, предшествует ли один элемент или следует за другим элементом или если один из этих элементов содержит другой. Он возвращает целое число, которое представляет отношение между сравниваемыми элементами.

Вот пример с одинаковыми элементами из предыдущего примера:

Foo

Bar

const container = document.querySelector('.container'); const h1 = document.querySelector('h1'); const h2 = document.querySelector('h2');// 20: h1 is contained by container and follows container container.compareDocumentPosition(h1); // 10: container contains h1 and precedes it h1.compareDocumentPosition(container);// 4: h2 follows h1 h1.compareDocumentPosition(h2);// 2: h1 precedes h2 h2.compareDocumentPosition(h1);

Значение, возвращенное из по сравнению со днями Это целое число, чьи биты представляют связь между узлами, относительно аргумента, данного этому методу.

Поэтому, учитывая синтаксис node.comparedocumentPostion (прочие) Смысл возвращенного значения:

1: Узлы не являются частью одного и того же документа 2: прочие предшествующие узлу 4: Другое следующее узла 8: В интервале NODENODE содержит узел 16: Другое место содержится узел.

Более чем один из биц может быть установлен так, поэтому в примере выше Container.comPoreDocumenPosition (H1) Возвращает 20, где вы можете ожидать 16, так как H1 содержится контейнера. Но H1 также следует за контейнером (4), поэтому полученное значение составляет 16+.

Подробнее, пожалуйста!

Вы можете наблюдать изменения в любом узле DOM через МутацияОбсеревер интерфейс. Это включает в себя изменения текста, добавляемые узлы или удаляемые из наблюдаемого узла или изменений в атрибуты узла.

МутацияОбсеревер является невероятно мощным API для наблюдения практически любое изменение, которое происходит на элементе DOM и его дочерним узлам.

Новый МутацияОбсеревер создается путем вызова своего конструктора с функцией обратного вызова. Этот обратный вызов будет вызван всякий раз, когда происходит изменение на наблюдаемом узле:

const observer = new MutationObserver(callback);

Наблюдать за элементом, нам нужно позвонить в Соблюдайте Способ наблюдателя с узлом, который следует наблюдать как первый параметр и объект с опциями в качестве второго параметра:

const target = document.querySelector('#container');
const observer = new MutationObserver(callback);
observer.observe(target, options);

Наблюдение за целью не начинается до Соблюдайте называется.

Этот объект параметров принимает следующие ключи:

атрибуты : При установлении True, изменения в атрибутах узла будут наблюдаться атрибутрFilter : Массив имени атрибутов для просмотра, когда атрибуты верны, и это не установлено, изменения на все атрибуты узла будут наблюдаться AttsicuteoldValue : При установлении true предыдущее значение атрибута будет записано всякий раз, когда происходит изменение Характердата : При установлении True это записывает изменения в текст текстового узла, поэтому это только работает только на Textnodes, а не HTMLELEMS. Для этого на работе наблюдается наблюдаемый узел, должен быть текстовым узлом или, если наблюдатель контролирует HTMLELEMENT, параметр «Подмер» необходимо установить значение TRUE, а также мониторировать изменения в детские узлы. Характердаталдвалею : При установлении TRUE, предыдущее значение разъединенных данных будет записано всякий раз, когда происходит изменение подделка : Установите true, также наблюдайте изменения в детских узлах наблюдаемого элемента. Полклейс : Установите true для мониторинга элемента для добавления и удаления дочерних узлов. Когда поддерево установлено на истинные дочерние элементы, также будут наблюдаться для сложения и удаления дочерних узлов.

Когда наблюдение элемента началось при вызове Соблюдайте обратный вызов, который был передан на МутацияОбсеревер Конструктор называется с массивом МутацияРектор Объекты, описывающие изменения, которые произошли и наблюдатель, который был вызван в качестве второго параметра.

А МутацияРектор Содержит следующие свойства:

Тип: тип изменения, атрибуты, символ и клиенты. Цель: элемент, изменившийся либо его атрибуты, данные о символах или добавленные элементы для детей: список добавленных узлов или пустой odelist, если никто не добавлял удаление: список удаленных узлов или пустой odelist, если никто не удалил атрибут: имя Из измененного атрибута или NULL, если атрибут не было никаких изменений, предыдущие: предыдущий брат добавленных или удаленных узлов или нулевой Nextsibling: следующий брат добавленных или удаленных узлов или нулей

Итак, скажем, мы хотим наблюдать изменения в атрибутах и дочерних узлах:

const target = document.querySelector('#container');
const callback = (mutations, observer) => {
  mutations.forEach(mutation => {
    switch (mutation.type) {
      case 'attributes':
        // the name of the changed attribute is in
        // mutation.attributeName
        // and its old value is in mutation.oldValue
        // the current value can be retrieved with 
        // target.getAttribute(mutation.attributeName)
        break;      case 'childList':
        // any added nodes are in mutation.addedNodes
        // any removed nodes are in mutation.removedNodes
        break;
    }
  });
};

const observer = new MutationObserver(callback);observer.observe(target, {
  attributes: true,
  attributeFilter: ['foo'], // only observe attribute 'foo'
  attributeOldValue: true,
  childList: true
});

Когда вы закончите, наблюдая за целью, вы можете отключить наблюдателя и при необходимости позвоните его Takerecords Способ получения любых отложенных мутаций, которые еще не были доставлены на обратный вызов:

const mutations = observer.takeRecords();
callback(mutations);
observer.disconnect();

Не бойтесь дома

Дом API является невероятно мощным и универсальным, хотя и Verbose API. Имейте в виду, что он предназначен для обеспечения низкоуровневых строительных блоков для разработчиков для создания абстракций, поэтому в том смысле его необходимо представлять собой влагосвязать, чтобы обеспечить однозначную и понятную API.

Дополнительные нажатия клавиш не должны отпугивать вас от использования его до полного потенциала.

Дом является важным знанием для каждого разработчика JavaScript, так как вы, вероятно, используете его каждый день. Не бойтесь и используйте его до полного потенциала.

Вы будете лучшим разработчиком для этого.

Первоначально опубликовано Medium.com