Одна из самых запутанных вещей при начале работы с Polymer (или WebComponents) заключается в том, что у вас больше нет только одного дерева DOM. У тебя есть больше. И вы должны отслеживать в своей голове, с кем вы работаете.
Модель трех деревьев лежит в основе Polymer и является «волшебным соусом», позволяющим инкапсулировать стили и скрипты, а также создавать компоненты, которые теоретически можно повторно использовать из одного веб-приложения в другое. через простой процесс импорта-копирования-вставки.
Итак, давайте начнем с того, как вы начинаете разрабатывать пользовательский компонент Polymer:
<dom-module id=”my-component”> <style> <!-- CSS for this element: have *no effect outside*!--> </style> <template> <!-— Local DOM --> ... <content> <!-- Light DOM: element-s children get rendered here --> </content> <template> <script> Polymer({ is: "my component", // ...component code }); </script> </dom-module>
Теперь вы видите, что сначала у вас есть:
1. Локальный DOM
Локальный DOM состоит из компонентов вашего тега ‹template›.
Существует два способа реализации локального DOM:
- Локальный DOM, реализованный как Shadow DOM — это «реальная» версия, которая фактически изолирует свое содержимое от всех внешних стилей CSS, даже от «сырых», необработанных стилей, например файл bootstrap.css или app.css, который содержит обычный старый CSS.
- Локальный DOM реализован как Shady DOM — это версия по умолчанию, включенная в Polymer 1.0, и она работает и в старых браузерах. Он только изолирует внутренности ваших полимерных компонентов от стилей, которые должным образом заключены в теги ‹style is=”custom-style”› (или в другие компоненты), которые должным образом предварительно обрабатывают свои стили. Вот почему он называется «облегченным полифиллом»: он эмулирует Shadow DOM, но не пытается сделать это на 100%, потому что это привело бы к тоннам сложного кода, который невозможно поддерживать, и множеству непонятных ошибок, как показал Polymer 0.5.
Если вы просматриваете полимерные компоненты с помощью инспектора вашего браузера, вот как вы заметите разницу между ними:
Shady DOM выглядит как обычный фрагмент дерева DOM с некоторыми дополнительными классами, такими как style-scope, которые позволяют творить чудеса. Shadow DOM otoh, очевидно, является специальной функцией браузера.
2. Светлый ДОМ
Теперь вы знаете, что внутри пользовательского полимерного компонента вы можете добавлять дочерние элементы и визуализировать дочерние элементы внутри ‹template› с помощью ‹content›. Итак, у вас может быть что-то вроде этого:
<my-custom-element> <h4>Funcky section title</h4> <p>Text funk lorem impsum…</p> </my-custom-element>
…а внутри ‹template› вашего компонента что-то вроде этого:
<dom-module id=”my-cutom-element”> ... <template> <div id=”funkySection”> <span class=”funky-section-drag-handle”></span> <content></content> </div> </template> ... </dom-module>
Подсветка DOM просто в этом отображаемом содержимом, ‹h4› и ‹p› в приведенном выше примере.
Подводя итог тому, что мы прошли до сих пор, мы имеем что-то вроде этого:
Теперь есть еще одна вещь, которая нас интересует. Стрелки с закрашенными головками на диаграмме выше показывают, какие правила CSS применяются к тем или иным объектам. Но что, если вы хотите применить настройки стиля к «внутренностям» полимерного компонента, т. е. к локальному и легкому дому, из внешнего стиля.
На этот вопрос есть два ответа:
- Не делайте этого, потому что это плохая идея: это нарушит всю инкапсуляцию, для которой был создан Polymer!
- Используйте /deep/ и, когда вам нужна более «хирургическая точность», используйте ::shadow
Вот как это работает:
my-custom-element::shadow .some-selector-from-local-dom { /* this will apply to nodes of the local (shady/shadow) dom of my-custom-element (but NOT TO LIGHT DOM NODES!) */ } my-custom-element /deep/ .some-selector-from-local-dom-of-child-of-child-of...-child-of-my-custom-element { /* this will apply to nodes of the local (shady/shadow) dom of my-custom-element AND ALL ITS DESCENDENTS */ } /* and from these you can obviously guess that you can write the "nuclear options" variants: */ body /deep/ .whatever {} html /deep/ .whatever {}
Последние два, очевидно, делают то, что вы ожидаете: они полностью игнорируют то, что вы используете Polymer или WebComponents… Поэтому, если вы обнаружите, что используете их очень часто, вам следует либо изменить способ написания фронт- завершить код или отказаться от Polymer и выбрать что-то более подходящее для вашего рабочего процесса.
Следующим шагом, если вы зашли так далеко, было бы перечитать документацию Polymer по Локальному DOM и Стилизации локального DOM. И, к сожалению, документов Polymer редко бывает достаточно. Вам также следует просмотреть Shadow DOM 101 и Shadow DOM 201, если вы используете Polymer или что-либо на основе веб-компонентов.
Я надеюсь, что это помогло всем новичкам в Polymer и его извращениях лучше понять вещи. Вещи могут быть немного запутанными, но они такие, какие есть, по вечной причине: браузеры должны поддерживать совместимость со всеми ошибками своего прошлого. Так что лучше научитесь любить эти запутанные способы… потому что вы Вы также найдете их, если покопаетесь в истоках полноценных фреймворков, таких как Ember.js, метафреймворков, таких как Angular, и «систем пользовательского интерфейса», таких как React. Они просто лучше умеют прятать ужасы в своих темных подвалах, а не оставлять их на виду у всех, как это делает Полимер…