diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:52 -0500 |
commit | 074785cea106179cb3305637055ab0a009ca74f2 (patch) | |
tree | e6ae371cccd642aa2b67f39752a2cdf1fd4eb040 /files/ru/web/web_components | |
parent | da78a9e329e272dedb2400b79a3bdeebff387d47 (diff) | |
download | translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.gz translated-content-074785cea106179cb3305637055ab0a009ca74f2.tar.bz2 translated-content-074785cea106179cb3305637055ab0a009ca74f2.zip |
initial commit
Diffstat (limited to 'files/ru/web/web_components')
3 files changed, 485 insertions, 0 deletions
diff --git a/files/ru/web/web_components/html_imports/index.html b/files/ru/web/web_components/html_imports/index.html new file mode 100644 index 0000000000..06dab35aba --- /dev/null +++ b/files/ru/web/web_components/html_imports/index.html @@ -0,0 +1,37 @@ +--- +title: HTML Импорты +slug: Web/Web_Components/HTML_Imports +translation_of: Web/Web_Components/HTML_Imports +--- +<div class="warning"> +<p>Firefox will not ship <em>HTML Imports</em> in its current form. See this <a href="https://hacks.mozilla.org/2015/06/the-state-of-web-components/">status update</a> for more information. Until there is a consensus on the standard or alternative mechanisms are worked out, you can use a polyfill such as Google's <code><a href="https://github.com/webcomponents/webcomponentsjs">webcomponents.js</a></code>.</p> +</div> + +<p><em>HTML Импорты</em> is intended to be the packaging mechanism for <a href="/en-US/docs/Web/Web_Components">web components</a>, but you can also use HTML Imports by itself.</p> + +<div>You import an HTML file by using a <a href="/en-US/docs/Web/HTML/Element/link"><code><link></code></a> tag in an HTML document like this: </div> + +<div> </div> + +<pre><link rel="import" href="myfile.html"></pre> + +<p><span style="line-height: 1.5;">The </span><code style="font-style: normal; line-height: 1.5;">import</code><span style="line-height: 1.5;"> </span><span style="line-height: 1.5;">link type </span><span style="line-height: 1.5;">is new.</span></p> + +<h2 id="Specification">Specification</h2> + +<table class="spec-table standard-table"> + <tbody> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + <tr> + <td>{{SpecName('HTML Imports', "", "")}}</td> + <td>{{Spec2('HTML Imports')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<p> </p> diff --git a/files/ru/web/web_components/index.html b/files/ru/web/web_components/index.html new file mode 100644 index 0000000000..e8ec0144cc --- /dev/null +++ b/files/ru/web/web_components/index.html @@ -0,0 +1,205 @@ +--- +title: Веб-компоненты +slug: Web/Web_Components +translation_of: Web/Web_Components +--- +<p>{{DefaultAPISidebar("Веб-компоненты")}}</p> + +<p>Веб-компоненты - это набор различных технологий, позволяющих создавать повторно используемые настраиваемые элементы с их функциональностью, инкапсулированной отдельно от остальной части вашего кода - и использовать их в ваших веб-приложениях.</p> + +<h2 id="Понятия_и_использование">Понятия и использование</h2> + +<p>Как разработчики, все мы знаем, что как можно больше повторного использования кода - хорошая идея. Традиционно это было не так просто для пользовательских структур разметки - подумайте о сложном HTML (и связанном с ним стиле и сценарии), которые вам иногда приходилось писать для визуализации пользовательских элементов управления UI, и о том, как их многократное использование может превратить вашу страницу в беспорядок если вы не будете осторожны.</p> + +<p>Веб-компоненты направлены на решение таких проблем - они состоят из трех основных технологий, которые можно использовать вместе для создания универсальных настраиваемых элементов с инкапсулированной функциональностью, которые можно повторно использовать где угодно, не опасаясь коллизий кода.</p> + +<ul> + <li><strong>Пользовательские элементы</strong>: набор API-интерфейсов JavaScript, позволяющих определять пользовательские элементы и их поведение, которые затем можно использовать по желанию в пользовательском интерфейсе.</li> + <li><strong>Shadow DOM</strong>: набор API-интерфейсов JavaScript для прикрепления инкапсулированного «теневого» дерева DOM к элементу, который отображается отдельно от DOM основного документа, и управления соответствующими функциями. Таким образом, вы можете сохранить функции элемента в секрете, поэтому для них можно создавать сценарии и стили, не опасаясь коллизий с другими частями документа.</li> + <li><strong>HTML templates</strong>: элементы {{HTMLElement("template")}} и {{HTMLElement("slot")}} позволяют создавать шаблоны разметки, которыx не видно на отображаемой странице. Затем их можно многократно использовать в качестве основы структуры настраиваемого элемента.</li> +</ul> + +<p>Базовый подход к реализации веб-компонента обычно выглядит примерно так:</p> + +<ol> + <li>Создайте класс, в котором вы указываете функциональность своего веб-компонента, используя синтаксис классов ECMAScript 2015 (дополнительную информацию см. в разделе <a href="https://wiki.developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Classes">Классы</a>).</li> + <li>Зарегистрируйте свой новый настраиваемый элемент с помощью метода {{domxref("CustomElementRegistry.define()")}}, передав ему имя элемента, который будет определен, класс или функцию, в которых указана его функцианальность, и, необязательно, от какого элемента он наследуется.</li> + <li>При необходимости прикрепите теневую DOM к настраиваемому элементу с помощью метода {{domxref("Element.attachShadow()")}}. Добавьте дочерние элементы, прослушиватели событий и т.д. в теневой DOM, используя обычные методы DOM.</li> + <li>При необходимости определите HTML template, используя {{htmlelement("template")}} и {{htmlelement("slot")}}. Снова используйте обычные методы DOM, чтобы клонировать шаблон и прикрепить его к вашей теневой DOM.</li> + <li>Используйте свой настраиваемый элемент везде, где хотите, на своей странице, как и любой обычный элемент HTML.</li> +</ol> + +<h2 id="Учебники">Учебники</h2> + +<dl> + <dt><a href="/ru/docs/Web/Web_Components/Using_custom_elements">Использование пользовательских элементов </a></dt> + <dd>Руководство, показывающее, как использовать функции настраиваемых элементов для создания простых веб-компонентов, а также рассказывает про обратные вызовы жизненного цикла и некоторые другие более сложные функции.</dd> + <dt><a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">Использование shadow DOM</a></dt> + <dd>Руководство, которое рассматривает основы теневой DOM, показывает, как прикрепить теневую DOM к элементу, добавлять к теневому дереву DOM, стилизовать его и многое другое.</dd> + <dt><a href="/ru/docs/Web/Web_Components/Using_templates_and_slots">Использование шаблонов и слотов</a></dt> + <dd>Руководство, показывающее, как определить повторно используемую структуру HTML с помощью элементов {{htmlelement("template")}} и {{htmlelement ("slot")}}, а затем использовать эту структуру внутри ваших веб-компонентов.</dd> +</dl> + +<h2 id="Справка">Справка</h2> + +<h3 id="Пользовательские_элементы">Пользовательские элементы</h3> + +<dl> + <dt>{{domxref("CustomElementRegistry")}}</dt> + <dd>Содержит функции, связанные с настраиваемыми элементами, в первую очередь с методом {{domxref("CustomElementRegistry.define()")}}, используемым для регистрации новых настраиваемых элементов, чтобы их можно было затем использовать в вашем документе.</dd> + <dt>{{domxref("Window.customElements")}}</dt> + <dd>Возвращает ссылку на объект <code>CustomElementRegistry</code>.</dd> + <dt><a href="/ru/docs/Web/Web_Components/Using_custom_elements#Использование_lifecycle_callbacks">Обратные вызовы жизненного цикла</a></dt> + <dd>Специальные функции обратного вызова, определенные внутри определения класса настраиваемого элемента, которые влияют на его поведение: + <ul> + <li><code>connectedCallback</code>: вызывается, когда настраиваемый элемент впервые подключается к DOM документа.</li> + <li><code>disconnectedCallback</code>: вызывается, когда пользовательский элемент отключается от DOM документа.</li> + <li><code>adoptedCallback</code>: вызывается, когда настраиваемый элемент перемещается в новый документ.</li> + <li><code>attributeChangedCallback</code>: вызывается при добавлении, удалении или изменении одного из атрибутов настраиваемого элемента.</li> + </ul> + </dd> + <dt>Расширения для создания пользовательских встроенных элементов</dt> + <dd> + <ul> + <li>Глобальный атрибут HTML {{htmlattrxref("is")}}: позволяет указать, что стандартный элемент HTML должен вести себя как зарегистрированный встроенный пользовательский элемент.</li> + <li>Параметр «is» метода {{domxref("Document.createElement()")}}: позволяет создать экземпляр стандартного HTML-элемента, который ведет себя как заданный зарегистрированный настраиваемый встроенный элемент.</li> + </ul> + </dd> + <dt>Псевдоклассы CSS</dt> + <dd>Псевдоклассы, относящиеся конкретно к настраиваемым элементам: + <ul> + <li>{{cssxref(":defined")}}: Соответствует любому заданному элементу, включая встроенные элементы и настраиваемые элементы, определенные с помощью <code>CustomElementRegistry.define()</code>.</li> + <li>{{cssxref(":host")}}: Выбирает теневой хост <a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">теневого DOM</a>, содержащего CSS, внутри которого он используется.</li> + <li>{{cssxref(":host()")}}: Выбирает теневой хост <a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">теневой DOM</a>, содержащий CSS, внутри которого он используется (так что вы можете выбрать пользовательский элемент изнутри его теневой DOM) - но только если селектор, указанный в качестве параметра функции, совпадает с теневым хостом.</li> + <li>{{cssxref(":host-context()")}}: Выбирает теневой хост <a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">теневой DOM</a>, содержащий CSS, внутри которого он используется (так что вы можете выбрать пользовательский элемент изнутри его теневой DOM) - но только если селектор, указанный в качестве параметра функции, совпадает с предком(-ами) теневого хоста в том месте, где он находится внутри иерархии DOM.</li> + </ul> + </dd> + <dt>Псевдоэлементы CSS</dt> + <dd>Псевдоэлементы, относящиеся конкретно к настраиваемым элементам: + <ul> + <li>{{cssxref("::part")}}: Представляет любой элемент в <a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">теневом дереве</a>, имеющий соответствующий атрибут {{HTMLAttrxRef("part")}}.</li> + </ul> + </dd> +</dl> + +<h3 id="Shadow_DOM">Shadow DOM</h3> + +<dl> + <dt>{{domxref("ShadowRoot")}}</dt> + <dd>Представляет корневой узел поддерева теневой модели DOM.</dd> + <dt>{{domxref("DocumentOrShadowRoot")}}</dt> + <dd>Миксин, определяющий функции, доступные для всех документов и теневых корневых узлов.</dd> + <dt>Расширения {{domxref("Element")}}</dt> + <dd>Расширения интерфейса <code>Element</code>, связанные с теневой DOM: + <ul> + <li>Метод {{domxref("Element.attachShadow()")}} прикрепляет теневое дерево DOM к указанному элементу.</li> + <li>Свойство {{domxref ("Element.shadowRoot")}} возвращает теневой корневой узел, прикрепленный к указанному элементу, или значение <code>null</code>, если корневой узел не прикреплен.</li> + </ul> + </dd> + <dt>Соответствующие дополнения {{domxref("Node")}}</dt> + <dd>Дополнения к интерфейсу <code>Node</code>, относящиеся к теневой DOM: + <ul> + <li>Метод {{domxref("Node.getRootNode()")}} возвращает корень объекта контекста, который необязательно включает теневой корневой узел, если он доступен.</li> + <li>Свойство {{domxref("Node.isConnected")}} возвращает логическое значение, указывающее, подключен ли узел (прямо или косвенно) к объекту контекста, например объект {{domxref("Document")}} в случае обычного DOM или {{domxref("ShadowRoot")}} в случае теневого DOM.</li> + </ul> + </dd> + <dt>Расширения {{domxref("Event")}}</dt> + <dd>Расширения интерфейса <code>Event</code>, относящиеся к теневой модели DOM: + <ul> + <li>{{domxref("Event.composed")}}: возвращает {{jsxref("Boolean")}}, который указывает, будет ли событие распространяться через границу теневой DOM в стандартную DOM (<code>true</code>) или нет (<code>false</code>).</li> + <li>{{domxref ("Event.composedPath")}}: возвращает путь к событию (объекты, для которых будут вызваны слушатели). Это не включает узлы в теневых деревьях, если теневой кореневой узел был создан с закрытым {{domxref("ShadowRoot.mode")}}.</li> + </ul> + </dd> +</dl> + +<h3 id="HTML_templates">HTML templates</h3> + +<dl> + <dt>{{htmlelement("template")}}</dt> + <dd>Содержит фрагмент HTML, который не отображается при первоначальной загрузке содержащего документа, но может отображаться во время выполнения с помощью JavaScript, который в основном используется в качестве основы для структур настраиваемых элементов. Связанный интерфейс DOM - {{domxref("HTMLTemplateElement")}}.</dd> + <dt>{{htmlelement("slot")}}</dt> + <dd>Заполнитель внутри веб-компонента, который можно заполнить собственной разметкой, что позволяет создавать отдельные деревья DOM и представлять их вместе. Связанный интерфейс DOM - {{domxref("HTMLSlotElement")}}.</dd> + <dt>Глобальный HTML атрибут <code><a href="/ru/docs/Web/HTML/Global_attributes/slot">slot</a></code></dt> + <dd>Назначает слот элементу в теневом дереве теневого DOM.</dd> + <dt>{{domxref("Slotable")}}</dt> + <dd>Миксин, реализованный как узлами {{domxref("Element")}}, так и {{domxref("Text")}}, определяющий функции, которые позволяют им стать содержимым элемента {{htmlelement("slot")}}. Миксин определяет один атрибут, {{domxref("Slotable.assignedSlot")}}, который возвращает ссылку на слот, в который вставлен узел.</dd> + <dt>{{domxref("Element")}} extensions</dt> + <dd>Расширения интерфейса <code>Element</code>, относящиеся к слотам: + <ul> + <li>{{domxref("Element.slot")}}: Возвращает имя слота теневого DOM, прикрепленного к элементу.</li> + </ul> + </dd> + <dt>Псевдоэлементы CSS</dt> + <dd>Псевдоэлементы, относящиеся конкретно к слотам: + <ul> + <li>{{cssxref("::slotted")}}: Соответствует любому содержимому, вставленному в слот.</li> + </ul> + </dd> + <dt>Событие {{event("slotchange")}}</dt> + <dd>Вызывается для экземпляра {{domxref("HTMLSlotElement")}} (элемент {{htmlelement("slot")}}) при изменении узла(-ов), содержащихся в этом слоте.</dd> +</dl> + +<h2 id="Примеры">Примеры</h2> + +<p>Мы создаем ряд примеров в репозитории GitHub с <a href="https://github.com/mdn/web-components-examples">примерами веб-компонентов</a>. Со временем будет добавлено больше.</p> + +<h2 id="Спецификации">Спецификации</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Спецификация</th> + <th scope="col">Статус</th> + <th scope="col">Комментарии</th> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG","scripting.html#the-template-element","<template> element")}}</td> + <td>{{Spec2("HTML WHATWG")}}</td> + <td>Определение {{HTMLElement("template")}}.</td> + </tr> + <tr> + <td>{{SpecName("HTML WHATWG","custom-elements.html#custom-elements","custom elements")}}</td> + <td>{{Spec2("HTML WHATWG")}}</td> + <td>Определение <a href="/ru/docs/Web/Web_Components/Использование_пользовательских_элементов">пользовательских HTML элементов</a></td> + </tr> + <tr> + <td>{{SpecName("DOM WHATWG","#shadow-trees","shadow trees")}}</td> + <td>{{Spec2("DOM WHATWG")}}</td> + <td>Определение <a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a></td> + </tr> + <tr> + <td>{{SpecName("HTML Imports", "", "")}}</td> + <td>{{Spec2("HTML Imports")}}</td> + <td>Начальное определение <a href="/ru/docs/Web/Web_Components/HTML_Imports">HTML импорта</a></td> + </tr> + <tr> + <td>{{SpecName("Shadow DOM", "", "")}}</td> + <td>{{Spec2("Shadow DOM")}}</td> + <td>Начальное определение <a href="/ru/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a></td> + </tr> + </tbody> +</table> + +<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2> + +<p>В основном:</p> + +<ul> + <li>Веб-компоненты по умолчанию поддерживаются в Firefox (версия 63), Chrome и Opera.</li> + <li>Safari поддерживает ряд функций веб-компонентов, но меньше, чем указанные выше браузеры.</li> + <li>Edge работает над реализацией.</li> +</ul> + +<p>Для получения подробной информации о поддержке определенных функций браузером обратитесь к перечисленным выше справочным страницам.</p> + +<h2 id="Смотрите_также">Смотрите также</h2> + +<ul> + <li><a href="https://www.webcomponents.org/">webcomponents.org</a> - сайт с примерами веб-компонентов, учебными пособиями и другой информацией.</li> + <li><a href="https://fast.design/" rel="noopener">FAST</a> - это библиотека веб-компонентов, созданная Microsoft, которая предлагает несколько пакетов для использования в зависимости от потребностей вашего проекта. <a href="https://github.com/microsoft/fast/tree/master/packages/web-components/fast-element" rel="noopener">Fast Element</a> - это легкое средство для простого создания производительных, эффективных с точки зрения памяти и совместимых со стандартами веб-компонентов. <a href="https://github.com/microsoft/fast/tree/master/packages/web-components/fast-foundation" rel="noopener">Fast Foundation</a> - это библиотека классов, шаблонов и других утилит веб-компонентов, построенная на основе fast-element, предназначенная для создания зарегистрированных веб-компонентов.</li> + <li><a href="https://github.com/hybridsjs/hybrids">Hybrids</a> - библиотека веб-компонентов с открытым исходным кодом, которая предпочитает простые объекты и чистые функции <code>class</code> и <code>this</code> синтаксису. Он предоставляет простой и функциональный API для создания пользовательских элементов.</li> + <li><a href="https://www.polymer-project.org/">Polymer</a> - каркас веб-компонентов Google - набор полифилов, улучшений и примеров. На данный момент самый простой способ кроссбраузерно использовать веб-компоненты.</li> + <li><a href="https://github.com/devpunks/snuggsi#readme">Snuggsi</a> - Простые веб-компоненты размером ~ 1 КБ, <em>включая полифил</em> - Все, что вам нужно, это браузер и базовое понимание классов HTML, CSS и JavaScript для продуктивной работы.</li> + <li><a href="https://github.com/slimjs/slim.js">Slim.js</a> - библиотека веб-компонентов с открытым исходным кодом - высокопроизводительная библиотека для быстрой и простой разработки компонентов; расширяемая, подключаемая и кросс-платформенная.</li> + <li><a href="https://stenciljs.com/">Stencil</a> - набор инструментов для создания многоразовых масштабируемых систем проектирования в веб-компонентах.</li> +</ul> diff --git a/files/ru/web/web_components/использование_пользовательских_элементов/index.html b/files/ru/web/web_components/использование_пользовательских_элементов/index.html new file mode 100644 index 0000000000..bcb5b5d733 --- /dev/null +++ b/files/ru/web/web_components/использование_пользовательских_элементов/index.html @@ -0,0 +1,243 @@ +--- +title: Использование пользовательских элементов +slug: Web/Web_Components/Использование_пользовательских_элементов +translation_of: Web/Web_Components/Using_custom_elements +--- +<div>{{DefaultAPISidebar("Web Components")}}</div> + +<p class="summary">Одна из ключевых особенностей стандарта Веб-компонент это возможность создавать пользовательские элементы на HTML-странице, инкапсулирующие функциональность, вместо того чтобы создавать длинyю, вложенную группу элементов, которые бы вместе реализовывали нужную пользовательскую фичу. Эта статья является вводной по использованию пользовательских HTML-компонент.</p> + +<div class="note"> +<p><strong>Заметка</strong>: Пользовательские элементы поддерживаются по умолчанию в Firefox, Chrome и Opera. Safari пока поддерживает только автономные пользовательские компоненты, Edge также работает над реализацией.</p> +</div> + +<h2 id="Высокоуровневый_обзор">Высокоуровневый обзор</h2> + +<p>Контроллером пользовательских элементов веб-документа является объект {{domxref("CustomElementRegistry")}} — этот элемент позволяет регистрировать пользовательские элементы на веб-странице, возвращает информацию о зарегистрированных элементах и т.п.</p> + +<p>Чтобы зарегистрировать пользовательский элемент на странице, используйте метод {{domxref("CustomElementRegistry.define()")}} method. Он принимает аргументы:</p> + +<ul> + <li>{{domxref("DOMString")}} - имя элемента. Обратите внимание, что в именах пользовательских элементах <a href="https://stackoverflow.com/questions/22545621/do-custom-elements-require-a-dash-in-their-name">должен содержаться дефис</a>; они не могут состоять только из одного слова.</li> + <li>Объект типа <a href="/en-US/docs/Web/JavaScript/Reference/Classes">class</a>, определяющий поведение элемента.</li> + <li>Опционально объект options, имеющий свойство <code>extends</code>, соответствующее встроенному элементу, от которого наследует объект.</li> +</ul> + +<p>К примеру, мы можем определить пользовательский элемент <a href="https://mdn.github.io/web-components-examples/word-count-web-component/">word-count element</a>:</p> + +<pre class="brush: js">customElements.define('word-count', WordCount, { extends: 'p' });</pre> + +<p>Этот элемент называется <code>word-count</code>, объект соответствующего класса называется <code>WordCount</code>, и он наследует элементу {{htmlelement("p")}}.</p> + +<p>Объект класса пользовательского элемента определяется с помощью синтаксиса классов ES 2015. Например, <code>WordCount</code> имеют следующую структуру:</p> + +<pre class="brush: js">class WordCount extends HTMLParagraphElement { + constructor() { + // Всегда первым делом вызывайте super() в конструкторе + super(); + + // Далее пишется функциональность элемента + + ... + } +}</pre> + +<p>Это простой пример, но его можно дополнить. Можно определить специальные lifecycle callbacks, которые будут вызваны в определенные моменты жизненного цикла элемента. Например, <code>connectedCallback</code> будет вызван, когда пользовательский элемент оказывается впервые встроен в DOM, а <code>attributeChangedCallback</code> вызывается, когда пользовательскому элементу добавляют, удаляют или изменяют какой-то аттрибут.</p> + +<p>Подробнее об этом в секции {{anch("Using the lifecycle callbacks")}} ниже.</p> + +<p>Есть два типа пользовательских элементов:</p> + +<ul> + <li><strong>Автономные пользователькие элементы</strong> независимы — они не наследуют встроенным HTML-элементам. Их используют на странице просто как обычный HTML-элемент. Например, <code><popup-info></code> или <code>document.createElement("popup-info")</code>.</li> + <li><strong>Модифицированные встроенные элементы</strong> наследуют базовым HTML-элементам. Чтобы создать один из них, вы определяете элемент, от которого они унаследованы (как в примерах выше), и используете их как обычный базовый элемент, но с добавлением атрибута/свойства с именем пользовательского элемента {{htmlattrxref("is")}}. Например <code><p is="word-count"></code>, или <code>document.createElement("p", { is: "word-count" })</code>.</li> +</ul> + +<h2 id="Разбор_простых_примеров">Разбор простых примеров</h2> + +<p>А сейчас давайте разберем еще несколько простых примеров, иллюстрирующих подробности создания пользовательских элементов.</p> + +<h3 id="Автономные_пользовательские_элементы">Автономные пользовательские элементы</h3> + +<p>Рассмотрим пример автономного пользовательского элемента — <code><a href="https://github.com/mdn/web-components-examples/tree/master/popup-info-box-web-component"><popup-info-box></a></code> (см. <a href="https://mdn.github.io/web-components-examples/popup-info-box-web-component/">работающий пример</a>). Он содержит изображение и строку, и встраивает изображение в страницу. Когда на изображение наводят фокус, компонент показывает всплывающую подсказку с текстом.</p> + +<p>Прежде всего файл JavaScript определяет класс <code>PopUpInfo</code>, наследующий от {{domxref("HTMLElement")}}. Автономные пользовательские элементы почти всегда наследуют <code>HTMLElement</code>.</p> + +<pre class="brush: js">class PopUpInfo extends HTMLElement { + constructor() { + // Всегда первым делом вызывайте super() в конструкторе + super(); + + // далее следует функциональность элемента + + ... + } +}</pre> + +<p>В этом фрагменте кода содержится определение конструктора {{jsxref("Classes.constructor","constructor")}} класса, которое всегда начинается с вызова <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/super">super()</a></code> чтобы отработала цепочка прототипного наследования.</p> + +<p>Внутри конструктора мы определяем всю функциональность, которую получит элемент при создании его объекта. В данном случае мы добавляем shadow root к пользовательскому элементу, производим манипуляции с DOM, чтобы создать определенную структуру shadow DOM внутри элемента — которая затем присоединяется к shadow root — и наконец добавляем CSS к shadow root, чтобы задать его стиль.</p> + +<pre class="brush: js">// Создание shadow root +var shadow = this.attachShadow({mode: 'open'}); + +// Создание spans +var wrapper = document.createElement('span'); +wrapper.setAttribute('class','wrapper'); +var icon = document.createElement('span'); +icon.setAttribute('class','icon'); +icon.setAttribute('tabindex', 0); +var info = document.createElement('span'); +info.setAttribute('class','info'); + +// Берем содержимое атрибута и добавляем его в span +var text = this.getAttribute('text'); +info.textContent = text; + +// Вставляем иконку +var imgUrl; +if(this.hasAttribute('img')) { + imgUrl = this.getAttribute('img'); +} else { + imgUrl = 'img/default.png'; +} +var img = document.createElement('img'); +img.src = imgUrl; +icon.appendChild(img); + +// Создаем CSS для shadow dom +var style = document.createElement('style'); + +style.textContent = '.wrapper {' + +// CSS truncated for brevity + +// добавляем созданные элементы к shadow dom + +shadow.appendChild(style); +shadow.appendChild(wrapper); +wrapper.appendChild(icon); +wrapper.appendChild(info);</pre> + +<p>Наконец, регистрируем пользовательский элемент в <code>CustomElementRegistry</code> с помощью метода <code>define()</code>, который упоминался ранее — в качестве параметров мы передаем ему имя элемента и имя класса, который содержит его функциональность:</p> + +<pre class="brush: js">customElements.define('popup-info', PopUpInfo);</pre> + +<p>Теперь он доступен для использования на нашей странице. В HTML мы используем его так:</p> + +<pre class="brush: html"><popup-info img="img/alt.png" text="Код валидации вашей карты (CVC) + это дополнительная мера безопасности — это последние 3 или 4 цифры + на обороте вашей карты."></pre> + +<div class="note"> +<p><strong>Замечение</strong>: Вы можете прочитать <a href="https://github.com/mdn/web-components-examples/blob/master/popup-info-box-web-component/main.js">полный исходный код на JavaScript</a> здесь.</p> +</div> + +<h3 id="Модифицированные_встроенные_элементы">Модифицированные встроенные элементы</h3> + +<p>Тепреь давайте взглянем на другой пример модифицированного пользовательского элемента — <a href="https://github.com/mdn/web-components-examples/tree/master/expanding-list-web-component">раскрывающийся список</a> (<a href="https://mdn.github.io/web-components-examples/expanding-list-web-component/">см. действующий пример</a>). Он превращает любой ненумерованный список в раскрывающееся/складывающееся меню.</p> + +<p>Первым делом определим класс элемента наподобие того, как это делалось выше:</p> + +<pre class="brush: js">class ExpandingList extends HTMLUListElement { + constructor() { + // Всегда первым делом вызываем super() в конструкторе + super(); + + // ниже следует функциональность элемента + + ... + } +}</pre> + +<p>Здесь мы не будем во всех подробностях описывать функциональность элемента, вы можете понять как он работает, посмотрев исходный код. Единственное принципиальное различие с предыдующим примером состоит в том, что мы используем интерфейс {{domxref("HTMLUListElement")}}, а не {{domxref("HTMLElement")}}. Так что у него есть все характеристики элемента {{htmlelement("ul")}}, плюс дополнительная функциональность, которую определили мы. Это и отличает модифицированный встроенный элемент от автономного пользовательского элемента.</p> + +<p>Далее мы регистрируем этот элемент с помощью метода <code>define()</code> как в прошлом примере, только на сей раз мы добавляем объект options, который определяет, какому встроенному элементу наследует данный:</p> + +<pre class="brush: js">customElements.define('expanding-list', ExpandingList, { extends: "ul" });</pre> + +<p>Встроенный элемент используется на веб-странице немного по-другому:</p> + +<pre class="brush: html"><ul is="expanding-list"> + + ... + +</ul></pre> + +<p>Вы задаете элемент <code><ul></code> как обычно, но указываете имя модифицированного элемента в атрибуте <code>is</code>.</p> + +<div class="note"> +<p><strong>Замечание</strong>: Полный <a href="https://github.com/mdn/web-components-examples/blob/master/expanding-list-web-component/main.js">исходный код на JavaScript</a> доступен здесь.</p> +</div> + +<h2 id="Использование_lifecycle_callbacks">Использование lifecycle callbacks</h2> + +<p>Вы можете определить несколько разных коллбеков в конструкторе пользовательских элементов, которые сработают на разных этапах жизненного цикла элемента:</p> + +<ul> + <li><code>connectedCallback</code>: Срабатывает, когда пользовательский элемент впервые добавляется в DOM.</li> + <li><code>disconnectedCallback</code>: Срабатывает, когда пользовательский элемент удаляется из DOM.</li> + <li><code>adoptedCallback</code>: Срабатывает, когда пользовательский элемент перемещен в новый документ.</li> + <li><code>attributeChangedCallback</code>: Срабатывает, когда пользовательскому элементу добавляют, удаляют или изменяют атрибут.</li> +</ul> + +<p>Посмотрим на них в действии. Код ниже взят из примера <a href="https://github.com/mdn/web-components-examples/tree/master/life-cycle-callbacks">life-cycle-callbacks</a> (<a href="https://mdn.github.io/web-components-examples/life-cycle-callbacks/">см. его в действии</a>). Это тривиальный пример, создающий на странице цветной квадрат. Вот как выглядит код пользовательского элемента:</p> + +<pre class="brush: html"><custom-square l="100" c="red"></custom-square></pre> + +<p>Конструктор класса очень простой — мы просто добавляем shadow DOM к элементу, а затем добавляем пустые элементы {{htmlelement("div")}} и {{htmlelement("style")}} к shadow root:</p> + +<pre class="brush: js">var shadow = this.attachShadow({mode: 'open'}); + +var div = document.createElement('div'); +var style = document.createElement('style'); +shadow.appendChild(style); +shadow.appendChild(div);</pre> + +<p>Наиболее важная функция в этом примере <code>updateStyle()</code> — она принимает элемент, находит его shadow root, находит его элемент <code><style></code>, и добавляет {{cssxref("width")}}, {{cssxref("height")}}, и {{cssxref("background-color")}} к стилям.</p> + +<pre class="brush: js">function updateStyle(elem) { + var shadow = elem.shadowRoot; + var childNodes = shadow.childNodes; + for(var i = 0; i < childNodes.length; i++) { + if(childNodes[i].nodeName === 'STYLE') { + childNodes[i].textContent = 'div {' + + ' width: ' + elem.getAttribute('l') + 'px;' + + ' height: ' + elem.getAttribute('l') + 'px;' + + ' background-color: ' + elem.getAttribute('c'); + } + } +}</pre> + +<p>Сами изменения стилей обрабатываются коллбеками жизненного цикла, находящимися внутри конструктора. <code>connectedCallback()</code> срабатывает, когда элемент встраивается в DOM — здесь мы запускаем функцию <code>updateStyle()</code> которая обсеспечивает, чтобы квадрат имел стиль, описанный в его атрибутах:</p> + +<pre class="brush: js">connectedCallback() { + console.log('Пользовательский элемент квадрат добавлен на страницу.'); + updateStyle(this); +}</pre> + +<p>коллбеки <code>disconnectedCallback()</code> и <code>adoptedCallback()</code> логируют простые сообщения на консоль, которые уведомляют нас, что элемент удален из DOM или перемещен на другую страницу:</p> + +<pre class="brush: js">disconnectedCallback() { + console.log('Пользователский элемент квадрат удален.'); +} + +adoptedCallback() { + console.log('Пользовательский элемент квадарат перемещен на другую страницу.'); +}</pre> + +<p>Коллбек <code>attributeChangedCallback()</code> запускается когда один из аттрибутов элемента меняется. Как видно из его свойств, можно воздействовать на индивидуальные аттрибуты, глядя на их имена, и новые и старые значения аттрибутов. В данном случае, однако, мы просто снова запускаем функцию <code>updateStyle()</code> чтобы убедиться, что атрибуты квадрата получили новые значения:</p> + +<pre class="brush: js">attributeChangedCallback(name, oldValue, newValue) { + console.log('Атрибуты пользовательского элемента квадрат изменились.'); + updateStyle(this); +}</pre> + +<p>Обратите внимание, что нужно наблюдать за атрибутами, чтобы запустить коллбек <code>attributeChangedCallback()</code> когда они изменятся. Это делается через вызов геттера <code>observedAttributes()</code> в конструкторе, который содержит оператор <code>return</code> возвращающий массив с именами атрибутов, которые вы хотите наблюдать:</p> + +<pre class="brush: js">static get observedAttributes() {return ['w', 'l']; }</pre> + +<p>В нашем случае он расположен в начале конструктора.</p> + +<div class="note"> +<p><strong>Замечение</strong>: Смотрите <a href="https://github.com/mdn/web-components-examples/blob/master/life-cycle-callbacks/main.js">полный исходный код на JavaScript</a> здесь.</p> +</div> |