Shadow Dom – не злодей из фильма о супергероях. Это тоже не темная сторона Дома. Shadow Dom – это просто способ устранения отсутствия инкапсуляции деревьев в модели объекта документа (или DOM для короткого).
Для веб -страницы обычно используется данные и виджеты из внешних источников. Без инкапсуляции стили могут повлиять на нежелательные части HTML, заставляя разработчиков использовать чрезмерно специфические селекторы и важные правила, чтобы избежать конфликтов в стиле.
Тем не менее, эти усилия, по -видимому, не являются очень эффективными при написании больших программ, и значительная часть времени разработки тратится на предотвращение столкновений CSS и JavaScript. API Shadow DOM стремится решить эти и другие проблемы, предоставляя механизм для инкапсуляции деревьев DOM.
Shadow Dom – одна из основных технологий, используемых для создания веб -компонентов; Два других являются пользовательскими элементами и шаблонами HTML. Спецификация веб -компонентов была первоначально предложена Google для упрощения разработки виджетов для Интернета.
Хотя три технологии предназначены для совместной работы, у вас есть свобода использовать каждую отдельно. Объем этого учебника ограничена тенью DOM.
Что такое Дом?
Прежде чем мы углубимся в то, как создать теневые DOMS, важно понять, что такое DOM. Модель объекта документа W3C (DOM) предоставляет интерфейс программирования прикладного программирования платформы и языка (API) для представления и манипулирования информации, хранящейся в документах HTML и XML.
С DOM программисты могут получить доступ, добавлять, удалять или изменять элементы и контент. DOM рассматривает веб -страницу как структуру дерева, причем каждая ветвь заканчивается узлом, и каждый узел удерживает объект, который может быть изменен с использованием языка сценариев, такого как JavaScript. Рассмотрим следующий HTML -документ:
Sample document
Heading
Link
Презентация DOM этого HTML заключается в следующем:
Все коробки на этой фигуре являются узлами.
Терминология, используемая для описания частей DOM, напоминают то, что в реальном мире те из семейного древа:
- Узел на один уровень выше данного узла является родителем этого узла
- Узел на один уровень ниже заданного узла – ребенок этого узла
- Узлы, у которых один и тот же родитель являются братьями и сестрами
- Все узлы выше данного узла, включая родительского и бабушки, называются предками этого узла
- Наконец, все узлы ниже данного узла называются потомками этого узла
Тип узла зависит от типа HTML -элемента, который он представляет. Тег HTML называется узлом элемента. Вложенные метки образуют дерево элементов. Текст в элементе называется текстовым узлом. Текстовый узел может не иметь детей; Вы можете думать об этом как о листе дерева.
Чтобы получить доступ к дереву, DOM предоставляет набор методов, с помощью которых программист может изменить содержание и структуру документа. Когда вы пишете Document.createElement (‘p’);, например, вы используете метод, предоставленный DOM. Без DOM JavaScript не поймет структуру документов HTML и XML.
Следующий код JavaScript показывает, как использовать методы DOM для создания двух элементов HTML, гнездо один внутри другого, установить текстовое содержимое и добавить их в тело документа:
const section = document.createElement('section');
const p = document.createElement('p');
p.textContent = 'Hello!';
section.appendChild(p);
document.body.appendChild(section);
Вот полученная структура DOM после запуска этого кода JavaScript:
Hello!
Что такое тень доми?
Инкапсуляция является фундаментальной особенностью объектно-ориентированного программирования, которая позволяет программисту ограничить несанкционированный доступ к некоторым компонентам объекта.
В соответствии с этим определением объект предоставляет интерфейс в форме общедоступных методов как способ взаимодействия с его данными. Таким образом, внутреннее представление объекта не доступно непосредственно извне определения объекта.
Shadow Dom приносит эту концепцию в HTML. Это позволяет вам связывать скрытый, разделенный DOM с элементом, что означает, что вы можете иметь локальную область для HTML и CSS. Теперь вы можете использовать более общие селекторы CSS, не беспокоясь о конфликтах именования, и стили больше не протекают и не применяются к элементам, которые они не должны были.
По сути, API Shadow DOM – это именно то, что разработчики библиотеки и виджетов должны были разделить структуру HTML, стиль и поведение от других частей кода.
Корень тени – самый верхний узел в теневой дереве. Это то, что прикрепляется к обычному узлу DOM при создании теневого DOM. Узел, который имеет корень тени, связан с ним, известен как теневой хост.
Вы можете прикрепить элементы к корне тени так же, как и к нормальному DOM. Узлы, связанные с корнем тени, образуют дерево тени. Диаграмма должна сделать это более ясным:
Термин Light DOM часто используется для отличия нормального DOM от Shadow Dom. Вместе тень Dom и Light Dom называются логическим DOM. Точка, в которой световой DOM отделен от теневого DOM, называется границей тени. Запросы DOM и правила CSS не могут перейти на другую сторону границы тени, создавая тем самым инкапсуляцию.
Создание тени Дом
Чтобы создать теневой DOM, вам необходимо прикрепить корень тени к элементу, используя метод element.attachshadow (). Вот синтаксис:
var shadowroot = element.attachShadow(shadowRootInit);
Давайте посмотрим на простой пример:
Default text
Этот код прикрепляет теневое дерево DOM к элементу DIV, идентификатор которого является хостом. Это дерево отделено от реальных детей Div, и все, что добавлено к нему, будет локальным для элемента хостинга.
Корень Shadow в Chrome Devtools.
Обратите внимание, как существующий элемент в #host заменяется корнем тени. Браузеры, которые не поддерживают Shadow Dom, будут использовать контент по умолчанию.
Теперь, добавляя CSS в основной документ, правила стиля не повлияют на The Shadow Dom:
Light DOM
Стили, определенные в свете, не могут пересечь границу тени. В результате только параграфы в свете DOM будут краснеть.
И наоборот, CSS, который вы добавляете в теневую DOM, является локальным для элемента хостинга и не влияет на другие элементы в DOM:
Light DOM
Вы также можете поместить правила стиля на внешнюю таблицу стилей, например:
shadowRoot.innerHTML = `Shadow DOM
`;
Чтобы получить ссылку на элемент, к которому прикреплен Shadowroot, вы можете использовать свойство хоста:
Чтобы сделать наоборот и получить ссылку на корень тени, организованный элементом, используйте свойство Shadowroot элемента:
Shadowroot Mod
При вызове метода element.attachshadow () для прикрепления корня тени необходимо указать режим инкапсуляции для дерева теневого DOM, передавая объект в качестве аргумента, в противном случае выбрасывается тип ENRERROR. Объект должен иметь свойство режима со значением либо открытого, либо закрытого.
Открытый корень Shadow позволяет использовать свойство Shadowroot stode Element для доступа к элементам корня Shadow извне корня, как показано в этом примере:
Light DOM
Но если свойство Mode имеет значение закрытого, пытаясь использовать JavaScript извне корня, чтобы получить доступ к элементам корня Shadow, бросает TypeError:
Light DOM
Когда режим установлен в закрытом, свойство Shadowroot возвращает NULL. Поскольку нулевое значение не имеет какого -либо имущества или метода, вызов QuerySelector () на него вызывает типов. Закрытый корень тени обычно используется браузерами, чтобы сделать внутренние внутренние элементы некоторых элементов недоступными и неизменными от JavaScript.
Чтобы определить, находится ли теневой DOM в открытом или закрытом режиме, вы можете обратиться к свойству режима корня Shadow:
На первый взгляд, закрытый теневой DOM выглядит очень удобно для авторов веб -компонентов, которые не хотят выставлять корень тени своих компонентов; Однако на практике нетрудно обойти закрытые теневые домики. В целом, усилия, необходимые для полной скрытия теневого DOM, больше, чем стоит.
Не все элементы HTML могут размещать тень Дом
Только ограниченный набор элементов может размещать тень Dom. В следующей таблице перечислены поддерживаемые элементы:
+----------------+----------------+----------------+ | article | aside | blockquote | +----------------+----------------+----------------+ | body | div | footer | +----------------+----------------+----------------+ | h1 | h2 | h3 | +----------------+----------------+----------------+ | h4 | h5 | h6 | +----------------+----------------+----------------+ | header | main | nav | +----------------+----------------+----------------+ | p | section | span | +----------------+----------------+----------------+
Попытка прикрепить дерево теневого DOM к любому другому элементу приводит к ошибке Domexception. Например:
document.createElement('img').attachShadow({mode: 'open'});
// => DOMException
Не разумно использовать элемент в качестве теневого хоста, поэтому не должно быть сюрпризом, что этот код бросает ошибку. Другая причина, по которой вы можете получить ошибку Domexception, заключается в том, что браузер уже использует этот элемент для размещения теневого DOM.
Браузеры автоматически прикрепляют теневой DOM к некоторым элементам
Shadow Dom существовал довольно давно, и браузеры использовали его, чтобы скрыть внутреннюю структуру таких элементов, как , и Анкет
Когда вы используете Элемент В вашем HTML браузер автоматически прикрепляет теневой DOM к элементу, который содержит элементы управления браузером по умолчанию. Но единственное, что видно в DOM, это Сам элемент:
Чтобы сделать корень тени таких элементов видимыми в Chrome, открывайте настройки Chrome Devtools (нажмите F1) и под раздел «Элементы» Проверка «Показать пользовательский агент Shadow Dom»:
После того, как опция «Показать пользовательский агент Shadow Dom» проверяется, узел Shadow Root и его дети становятся видимыми. Вот как включен один и тот же код после этого параметра:
Хостинг теневого DOM на пользовательском элементе
Пользовательский элемент, созданный пользовательским API Elements, может размещать теневой DOM, как и любой другой элемент. Рассмотрим следующий пример:
Этот код создает автономный пользовательский элемент, который размещает теневой DOM. Для этого он вызывает метод CustomElements.Define () с именем элемента в качестве первого аргумента и объектом класса в качестве второго аргумента. Класс расширяет HTMlelement и определяет поведение элемента.
Внутри конструктора Super () используется для установления цепочки прототипа, и к элементу прикреплена теневого корня к пользовательскому элементу. Теперь, когда вы используете на своей странице, он создает свой собственный тень Dom:
Имейте в виду, что действительный пользовательский элемент не может быть единым словом и должен иметь дефис (-) в его названии. Например, Myelement Нельзя использовать в качестве имени для пользовательского элемента и выбросит ошибку Domexception.
Стилизация элемента хоста
Обычно, чтобы стилизовать элемент хоста, вы добавите CSS в Light Dom, потому что именно там находится элемент хоста. Но что, если вам нужно стилизовать элемент хоста из The Shadow Dom?
Вот где входит функция псевдо-класса Host (). Этот селектор позволяет вам получить доступ к хосту Shadow из любого места в корне Shadow. Вот пример:
Стоит отметить, что: хост действителен только в корне тени. Также имейте в виду, что правила стиля, определенные за пределами корня тени, имеют более высокую специфичность, чем правила, определенные в: хост.
Например, #host {font-size: 16px; } бьет Shadow Dom's: Host {font-size: 20px; }. Это на самом деле полезно, потому что он позволяет вам определить стиль по умолчанию для вашего компонента и позволить пользователю компонента переопределить ваш стиль. Единственное исключение - важные правила, которые имеют более высокую специфичность внутри теневого DOM.
Вы также можете передать селектор в качестве аргумента: host (), который позволяет вам нацелиться на хост, только если он соответствует указанному селектору. Другими словами, это позволяет вам нацелиться на разные состояния одного и того же хоста:
Стиль на основе контекста
Чтобы выбрать хост корня Shadow, который находится внутри конкретного предка, вы можете использовать функцию псевдокласса Host-context (). Например:
:host-context(.main) {
font-weight: bold;
}
Этот код CSS выбирает теневой хост только в том случае, если он является потоком .main:
: host-context () особенно полезен для темы, потому что он позволяет автору создавать компонент на основе контекста, в котором он используется.
Стиль крючки
Интересным аспектом Shadow Dom является его способность создавать «заполнители в стиле» и позволить пользователю заполнить их. Это можно сделать с помощью CSS пользовательские свойства Анкет Давайте посмотрим на простой пример:
Этот теневой DOM позволяет пользователям переопределять размер шрифта своих абзацев. Значение устанавливается с использованием пользовательской нотации свойств (-размер: 20px), а теневой DOM извлекает значение, используя функцию var () (Font-Size: var (-размер, 16px)). С точки зрения концепции, это похоже на то, как работает элемент.
Наследуемые стили
Shadow Dom позволяет вам создавать изолированные элементы DOM без видимости селектора извне, но это не означает, что унаследованные свойства не пройдут через границу тени.
Определенные свойства, такие как цвет, фон и семейство шрифтов, проходят границу тени и применяются к тени. Таким образом, по сравнению с iframe, теневой DOM не является очень сильным барьером.
Light DOM
Обходной путь прост: сбросить наследуемые стили к их первоначальному значению, объявив все: начальные, например:
Light DOM
В этом примере элементы вынуждены вернуться к начальному состоянию, поэтому стили, пересекающие границу тени, не имеют эффекта.
Событие ретаргетинг
Событие, запускаемое в теневой DOM, может пересечь границу тени и пузырьте свет; Тем не менее, значение Event.Target автоматически изменяется, так что выглядит так, как будто событие происходило из элемента хоста, который содержит теневое дерево, а не фактический элемент.
Это изменение известно как ретаргетинг событий, и рассуждение о нем состоит в том, чтобы сохранить инкапсуляцию Shadow DOM. Рассмотрим следующий пример:
Этот код журналов На консоли, когда вы нажимаете в любом месте в Shadow Dom, поэтому слушатель не может увидеть фактический элемент, который отправил событие.
Однако ретаргетинг не происходит в Shadow Dom, и вы можете легко найти фактический элемент, с которым связано событие:
Обратите внимание, что не все события распространяются из Shadow Dom. Те, которые делают, возвращаются, но другие просто игнорируются. Если вы используете Пользовательские события Вам нужно использовать Compende: True Flag, в противном случае событие не будет пузыриться из границы тени.
Shadow Dom v0 vs. v1
Оригинальная версия спецификации Shadow DOM была реализована в Chrome 25 и была известна как Shadow Dom V0 в то время. Обновленная версия спецификации улучшает многие аспекты API Shadow DOM.
Например, элемент больше не может размещать более одного Dom Shadow, а некоторые элементы не могут разместить теневой DOM вообще. Нарушение этих правил вызывает ошибку.
Кроме того, Shadow Dom v1 предоставляет набор новых функций, таких как открытый режим Shadow, Swarkback Sent и многое другое. Вы можете найти полное сравнение по бок по бок V0 и V1 Здесь написано одним из авторов спецификации. Полное описание Shadow Dom v1 можно найти в W3C Анкет
Поддержка браузера для Shadow Dom v1
На момент написания этой статьи Firefox и Chrome полностью поддерживают Shadow Dom v1. К сожалению, Edge еще не внедрил V1, и Safari частично поддерживает его. Обновленный список поддерживаемых браузеров доступен на Могу ли я использовать... .
Чтобы реализовать DOM в браузерах, которые не поддерживают Shadow Dom v1, вы можете использовать тенистость и Shadycss Полифил.
Завершая
Отсутствие инкапсуляции в DOM долгое время было проблематичным для веб -разработчиков. API Shadow DOM предлагает элегантное решение этой проблемы, давая нам возможность создавать Scoped DOM.
Теперь столкновения в стиле больше не являются источником беспокойства, и селекторы не выходят из -под контроля. The Shadow Dom - это изменение игры для разработчиков виджетов. Это огромный плюс, чтобы иметь возможность создавать виджеты, которые инкапсулируются на остальной части страницы и не влияют на наличие других таблиц стилей и сценариев.
Как упоминалось ранее, веб -компоненты состоит из трех основных технологий, и Shadow Dom является ключевой его частью. Надеемся, что после прочтения этого поста вам будет легче понять, как все три технологии работают вместе для создания веб -компонентов.
У вас есть несколько советов? Дайте нам знать об этом в комментариях!
Plug: Logrocket, DVR для веб -приложений
https://logrocket.com/signup/
Logrocket это инструмент регистрации фронта, который позволяет вам воспроизводить проблемы, как будто они произошли в вашем собственном браузере. Вместо того, чтобы догадаться, почему возникают ошибки, или просить пользователей экрана и журнала дамп, Logrocket позволяет воспроизвести сеанс, чтобы быстро понять, что пошло не так. Он отлично работает с любым приложением, независимо от фреймворта, и имеет плагины для регистрации дополнительного контекста из Redux, Vuex и @ngrx/Store.
В дополнение к журналам Redux и состоянию регистрации журналы консоли Logrocket записывают, ошибки JavaScript, StackTraces, сетевые запросы/ответы с заголовками + BODES, метаданные браузера и пользовательские журналы. Он также приказывает DOM записывать HTML и CSS на странице, воссоздавая видеопроблемные видео даже самых сложных одностраничных приложений.
Попробуйте бесплатно Анкет
Пост Понимание Shadow Dom v1 появился первым на Logrocke Blog Анкет
Оригинал: "https://dev.to/bnevilleoneill/understanding-shadow-dom-v1-3oa"