# Свои элементы: Custom Elements Платформа "веб-компоненты" включает в себя несколько стандартов [Web Components](http://www.w3.org/standards/techs/components#w3c_all), которые находятся в разработке. Начнём мы со стандарта [Custom Elements](http://www.w3.org/TR/custom-elements/), который позволяет создавать свои типы элементов. [cut] ## Зачем Custom Elements? Критично настроенный читатель скажет: "Зачем ещё стандарт для создания своих элементов? Я могу создать любой элемент и прямо сейчас! В любом из современных браузеров можно писать любой HTML, используя свои теги: ``. Или создавать элементы из JavaScript при помощи `document.createElement('mytag')`. В чём же разница?" Она в том, что обычно элемент с нестандартным названием (например ``) воспринимается браузером, как нечто неопределённо-непонятное. Ему соответствует класс [HTMLUnknownElement](http://www.w3.org/TR/html5/dom.html#htmlunknownelement), и у него нет каких-либо особых методов. **Стандарт Custom Elements позволяет описывать для новых элементов свои свойства, методы, объявлять свой DOM, подобие конструктора и многое другое.** Давайте посмотрим это на примерах. [warn header="Для примеров рекомендуется Chrome"] Так как спецификация не окончательна, то для запуска примеров рекомендуется использовать Google Chrome, лучше -- последнюю сборку [Chrome Canary](https://www.google.ru/chrome/browser/canary.html), в которой, как правило, отражены последние изменения. [/warn] ## Новый элемент Для описания нового элемента используется вызов `document.registerElement(имя, { prototype: прототип })`. Здесь: Вот, к примеру, новый элемент ``: ```html *!* */!* 0 ``` Использовать новый элемент в HTML можно и до его объявления через `registerElement`. Для этого в браузере предусмотрен специальный режим "обновления" существующих элементов. Если браузер видит элемент с неизвестным именем, в котором есть дефис `-` (такие элементы называются "unresolved"), то:
  • Он ставит такому элементу специальный CSS-псевдокласс `:unresolved`, для того, чтобы через CSS можно было показать, что он ещё "не подгрузился".
  • При вызове `registerElement` такие элементы автоматически обновятся до нужного класса.
В примере ниже регистрация элемента происходит через 2 секунды после его появления в разметке: ```html Hello, world! ``` Можно создавать такие элементы и в JavaScript -- обычным вызовом `createElement`: ```js var timer = document.createElement('my-timer'); ``` ## Расширение встроенных элементов Выше мы видели пример создания элемента на основе базового `HTMLElement`. Но можно расширить и другие, более конкретные HTML-элементы. Для расширения встроенных элементов у `registerElement` предусмотрен параметр `extends`, в котором можно задать, какой тег мы расширяем. Например, кнопку: ```html ``` Важные детали:
Прототип теперь наследует не от `HTMLElement`, а от `HTMLButtonElement`
Чтобы расширить элемент, нужно унаследовать прототип от его класса.
В HTML указывается при помощи атрибута `is="..."`
Это принципиальное отличие разметки от обычного объявления без `extends`. Теперь `` работать не будет, нужно использовать исходный тег и `is`.
Работают методы, стили и события кнопки.
При клике на кнопку её не отличишь от встроенной. И всё же, это новый элемент, со своими методами, в данном случае `tick`.
При создании нового элемента в JS, если используется `extends`, необходимо указать и исходный тег в том числе: ```js var timer = document.createElement("button", "my-timer"); ``` ## Жизненный цикл В прототипе своего элемента мы можем задать специальные методы, которые будут вызываться при создании, добавлении и удалении элемента из DOM:
`createdCallback`Элемент создан
`attachedCallback`Элемент добавлен в документ
`detachedCallback`Элемент удалён из документа
`attributeChangedCallback(name, prevValue, newValue)`Атрибут добавлен, изменён или удалён
Как вы, наверняка, заметили, `createdCallback` является подобием конструктора. Он вызывается только при создании элемента, поэтому всю дополнительную инициализацию имеет смысл описывать в нём. Давайте используем `createdCallback`, чтобы инициализовать таймер, а `attachedCallback` -- чтобы автоматически запускать таймер при вставке в документ: ```html 0 ``` ## Итого Мы рассмотрели, как создавать свои DOM-элементы при помощи стандарта [Custom Elements](http://www.w3.org/TR/custom-elements/). Далее мы перейдём к изучению дополнительных возможностей по работе с DOM.