Одна из самых запутанных вещей при начале работы с 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 применяются к тем или иным объектам. Но что, если вы хотите применить настройки стиля к «внутренностям» полимерного компонента, т. е. к локальному и легкому дому, из внешнего стиля.

На этот вопрос есть два ответа:

  1. Не делайте этого, потому что это плохая идея: это нарушит всю инкапсуляцию, для которой был создан Polymer!
  2. Используйте /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. Они просто лучше умеют прятать ужасы в своих темных подвалах, а не оставлять их на виду у всех, как это делает Полимер…