From 074785cea106179cb3305637055ab0a009ca74f2 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:42:52 -0500 Subject: initial commit --- .../ru/web/web_components/html_imports/index.html | 37 ++++ files/ru/web/web_components/index.html | 205 +++++++++++++++++ .../index.html" | 243 +++++++++++++++++++++ 3 files changed, 485 insertions(+) create mode 100644 files/ru/web/web_components/html_imports/index.html create mode 100644 files/ru/web/web_components/index.html create mode 100644 "files/ru/web/web_components/\320\270\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\321\201\320\272\320\270\321\205_\321\215\320\273\320\265\320\274\320\265\320\275\321\202\320\276\320\262/index.html" (limited to 'files/ru/web/web_components') 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 +--- +
+

Firefox will not ship HTML Imports in its current form. See this status update 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 webcomponents.js.

+
+ +

HTML Импорты is intended to be the packaging mechanism for web components, but you can also use HTML Imports by itself.

+ +
You import an HTML file by using a <link> tag in an HTML document like this: 
+ +
 
+ +
<link rel="import" href="myfile.html">
+ +

The import link type is new.

+ +

Specification

+ + + + + + + + + + + + + + +
SpecificationStatusComment
{{SpecName('HTML Imports', "", "")}}{{Spec2('HTML Imports')}} 
+ +

 

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 +--- +

{{DefaultAPISidebar("Веб-компоненты")}}

+ +

Веб-компоненты - это набор различных технологий, позволяющих создавать повторно используемые настраиваемые элементы с их функциональностью, инкапсулированной отдельно от остальной части вашего кода - и использовать их в ваших веб-приложениях.

+ +

Понятия и использование

+ +

Как разработчики, все мы знаем, что как можно больше повторного использования кода - хорошая идея. Традиционно это было не так просто для пользовательских структур разметки - подумайте о сложном HTML (и связанном с ним стиле и сценарии), которые вам иногда приходилось писать для визуализации пользовательских элементов управления UI, и о том, как их многократное использование может превратить вашу страницу в беспорядок если вы не будете осторожны.

+ +

Веб-компоненты направлены на решение таких проблем - они состоят из трех основных технологий, которые можно использовать вместе для создания универсальных настраиваемых элементов с инкапсулированной функциональностью, которые можно повторно использовать где угодно, не опасаясь коллизий кода.

+ + + +

Базовый подход к реализации веб-компонента обычно выглядит примерно так:

+ +
    +
  1. Создайте класс, в котором вы указываете функциональность своего веб-компонента, используя синтаксис классов ECMAScript 2015 (дополнительную информацию см. в разделе Классы).
  2. +
  3. Зарегистрируйте свой новый настраиваемый элемент с помощью метода {{domxref("CustomElementRegistry.define()")}}, передав ему имя элемента, который будет определен, класс или функцию, в которых указана его функцианальность, и, необязательно, от какого элемента он наследуется.
  4. +
  5. При необходимости прикрепите теневую DOM к настраиваемому элементу с помощью метода {{domxref("Element.attachShadow()")}}. Добавьте дочерние элементы, прослушиватели событий и т.д. в теневой DOM, используя обычные методы DOM.
  6. +
  7. При необходимости определите HTML template, используя {{htmlelement("template")}} и {{htmlelement("slot")}}. Снова используйте обычные методы DOM, чтобы клонировать шаблон и прикрепить его к вашей теневой DOM.
  8. +
  9. Используйте свой настраиваемый элемент везде, где хотите, на своей странице, как и любой обычный элемент HTML.
  10. +
+ +

Учебники

+ +
+
Использование пользовательских элементов
+
Руководство, показывающее, как использовать функции настраиваемых элементов для создания простых веб-компонентов, а также рассказывает про обратные вызовы жизненного цикла и некоторые другие более сложные функции.
+
Использование shadow DOM
+
Руководство, которое рассматривает основы теневой DOM, показывает, как прикрепить теневую DOM к элементу, добавлять к теневому дереву DOM, стилизовать его и многое другое.
+
Использование шаблонов и слотов
+
Руководство, показывающее, как определить повторно используемую структуру HTML с помощью элементов {{htmlelement("template")}} и {{htmlelement ("slot")}}, а затем использовать эту структуру внутри ваших веб-компонентов.
+
+ +

Справка

+ +

Пользовательские элементы

+ +
+
{{domxref("CustomElementRegistry")}}
+
Содержит функции, связанные с настраиваемыми элементами, в первую очередь с методом {{domxref("CustomElementRegistry.define()")}}, используемым для регистрации новых настраиваемых элементов, чтобы их можно было затем использовать в вашем документе.
+
{{domxref("Window.customElements")}}
+
Возвращает ссылку на объект CustomElementRegistry.
+
Обратные вызовы жизненного цикла
+
Специальные функции обратного вызова, определенные внутри определения класса настраиваемого элемента, которые влияют на его поведение: +
    +
  • connectedCallback: вызывается, когда настраиваемый элемент впервые подключается к DOM документа.
  • +
  • disconnectedCallback: вызывается, когда пользовательский элемент отключается от DOM документа.
  • +
  • adoptedCallback: вызывается, когда настраиваемый элемент перемещается в новый документ.
  • +
  • attributeChangedCallback: вызывается при добавлении, удалении или изменении одного из атрибутов настраиваемого элемента.
  • +
+
+
Расширения для создания пользовательских встроенных элементов
+
+
    +
  • Глобальный атрибут HTML {{htmlattrxref("is")}}: позволяет указать, что стандартный элемент HTML должен вести себя как зарегистрированный встроенный пользовательский элемент.
  • +
  • Параметр «is» метода {{domxref("Document.createElement()")}}: позволяет создать экземпляр стандартного HTML-элемента, который ведет себя как заданный зарегистрированный настраиваемый встроенный элемент.
  • +
+
+
Псевдоклассы CSS
+
Псевдоклассы, относящиеся конкретно к настраиваемым элементам: +
    +
  • {{cssxref(":defined")}}: Соответствует любому заданному элементу, включая встроенные элементы и настраиваемые элементы, определенные с помощью CustomElementRegistry.define().
  • +
  • {{cssxref(":host")}}: Выбирает теневой хост теневого DOM, содержащего CSS, внутри которого он используется.
  • +
  • {{cssxref(":host()")}}: Выбирает теневой хост теневой DOM, содержащий CSS, внутри которого он используется (так что вы можете выбрать пользовательский элемент изнутри его теневой DOM) - но только если селектор, указанный в качестве параметра функции, совпадает с теневым хостом.
  • +
  • {{cssxref(":host-context()")}}: Выбирает теневой хост теневой DOM, содержащий CSS, внутри которого он используется (так что вы можете выбрать пользовательский элемент изнутри его теневой DOM) - но только если селектор, указанный в качестве параметра функции, совпадает с предком(-ами) теневого хоста в том месте, где он находится внутри иерархии DOM.
  • +
+
+
Псевдоэлементы CSS
+
Псевдоэлементы, относящиеся конкретно к настраиваемым элементам: +
    +
  • {{cssxref("::part")}}: Представляет любой элемент в теневом дереве, имеющий соответствующий атрибут {{HTMLAttrxRef("part")}}.
  • +
+
+
+ +

Shadow DOM

+ +
+
{{domxref("ShadowRoot")}}
+
Представляет корневой узел поддерева теневой модели DOM.
+
{{domxref("DocumentOrShadowRoot")}}
+
Миксин, определяющий функции, доступные для всех документов и теневых корневых узлов.
+
Расширения {{domxref("Element")}}
+
Расширения интерфейса Element, связанные с теневой DOM: +
    +
  • Метод {{domxref("Element.attachShadow()")}} прикрепляет теневое дерево DOM к указанному элементу.
  • +
  • Свойство {{domxref ("Element.shadowRoot")}} возвращает теневой корневой узел, прикрепленный к указанному элементу, или значение null, если корневой узел не прикреплен.
  • +
+
+
Соответствующие дополнения {{domxref("Node")}}
+
Дополнения к интерфейсу Node, относящиеся к теневой DOM: +
    +
  • Метод {{domxref("Node.getRootNode()")}} возвращает корень объекта контекста, который необязательно включает теневой корневой узел, если он доступен.
  • +
  • Свойство {{domxref("Node.isConnected")}} возвращает логическое значение, указывающее, подключен ли узел (прямо или косвенно) к объекту контекста, например объект {{domxref("Document")}} в случае обычного DOM или {{domxref("ShadowRoot")}} в случае теневого DOM.
  • +
+
+
Расширения {{domxref("Event")}}
+
Расширения интерфейса Event, относящиеся к теневой модели DOM: +
    +
  • {{domxref("Event.composed")}}: возвращает {{jsxref("Boolean")}}, который указывает, будет ли событие распространяться через границу теневой DOM в стандартную DOM (true) или нет (false).
  • +
  • {{domxref ("Event.composedPath")}}: возвращает путь к событию (объекты, для которых будут вызваны слушатели). Это не включает узлы в теневых деревьях, если теневой кореневой узел был создан с закрытым {{domxref("ShadowRoot.mode")}}.
  • +
+
+
+ +

HTML templates

+ +
+
{{htmlelement("template")}}
+
Содержит фрагмент HTML, который не отображается при первоначальной загрузке содержащего документа, но может отображаться во время выполнения с помощью JavaScript, который в основном используется в качестве основы для структур настраиваемых элементов. Связанный интерфейс DOM - {{domxref("HTMLTemplateElement")}}.
+
{{htmlelement("slot")}}
+
Заполнитель внутри веб-компонента, который можно заполнить собственной разметкой, что позволяет создавать отдельные деревья DOM и представлять их вместе. Связанный интерфейс DOM - {{domxref("HTMLSlotElement")}}.
+
Глобальный HTML атрибут slot
+
Назначает слот элементу в теневом дереве теневого DOM.
+
{{domxref("Slotable")}}
+
Миксин, реализованный как узлами {{domxref("Element")}}, так и {{domxref("Text")}}, определяющий функции, которые позволяют им стать содержимым элемента {{htmlelement("slot")}}. Миксин определяет один атрибут, {{domxref("Slotable.assignedSlot")}}, который возвращает ссылку на слот, в который вставлен узел.
+
{{domxref("Element")}} extensions
+
Расширения интерфейса Element, относящиеся к слотам: +
    +
  • {{domxref("Element.slot")}}: Возвращает имя слота теневого DOM, прикрепленного к элементу.
  • +
+
+
Псевдоэлементы CSS
+
Псевдоэлементы, относящиеся конкретно к слотам: +
    +
  • {{cssxref("::slotted")}}: Соответствует любому содержимому, вставленному в слот.
  • +
+
+
Событие {{event("slotchange")}}
+
Вызывается для экземпляра {{domxref("HTMLSlotElement")}} (элемент {{htmlelement("slot")}}) при изменении узла(-ов), содержащихся в этом слоте.
+
+ +

Примеры

+ +

Мы создаем ряд примеров в репозитории GitHub с примерами веб-компонентов. Со временем будет добавлено больше.

+ +

Спецификации

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
СпецификацияСтатусКомментарии
{{SpecName("HTML WHATWG","scripting.html#the-template-element","<template> element")}}{{Spec2("HTML WHATWG")}}Определение {{HTMLElement("template")}}.
{{SpecName("HTML WHATWG","custom-elements.html#custom-elements","custom elements")}}{{Spec2("HTML WHATWG")}}Определение пользовательских HTML элементов
{{SpecName("DOM WHATWG","#shadow-trees","shadow trees")}}{{Spec2("DOM WHATWG")}}Определение Shadow DOM
{{SpecName("HTML Imports", "", "")}}{{Spec2("HTML Imports")}}Начальное определение HTML импорта
{{SpecName("Shadow DOM", "", "")}}{{Spec2("Shadow DOM")}}Начальное определение Shadow DOM
+ +

Совместимость с браузерами

+ +

В основном:

+ + + +

Для получения подробной информации о поддержке определенных функций браузером обратитесь к перечисленным выше справочным страницам.

+ +

Смотрите также

+ + diff --git "a/files/ru/web/web_components/\320\270\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\321\201\320\272\320\270\321\205_\321\215\320\273\320\265\320\274\320\265\320\275\321\202\320\276\320\262/index.html" "b/files/ru/web/web_components/\320\270\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\321\201\320\272\320\270\321\205_\321\215\320\273\320\265\320\274\320\265\320\275\321\202\320\276\320\262/index.html" new file mode 100644 index 0000000000..bcb5b5d733 --- /dev/null +++ "b/files/ru/web/web_components/\320\270\321\201\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\320\275\320\270\320\265_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\214\321\201\320\272\320\270\321\205_\321\215\320\273\320\265\320\274\320\265\320\275\321\202\320\276\320\262/index.html" @@ -0,0 +1,243 @@ +--- +title: Использование пользовательских элементов +slug: Web/Web_Components/Использование_пользовательских_элементов +translation_of: Web/Web_Components/Using_custom_elements +--- +
{{DefaultAPISidebar("Web Components")}}
+ +

Одна из ключевых особенностей стандарта Веб-компонент это возможность создавать пользовательские элементы на HTML-странице, инкапсулирующие функциональность, вместо того чтобы создавать длинyю, вложенную группу элементов, которые бы вместе реализовывали нужную пользовательскую фичу. Эта статья является вводной по использованию пользовательских HTML-компонент.

+ +
+

Заметка: Пользовательские элементы поддерживаются по умолчанию в Firefox, Chrome и Opera. Safari пока поддерживает только автономные пользовательские компоненты, Edge также работает над реализацией.

+
+ +

Высокоуровневый обзор

+ +

Контроллером пользовательских элементов веб-документа является объект {{domxref("CustomElementRegistry")}} — этот элемент позволяет регистрировать пользовательские элементы на веб-странице, возвращает информацию о зарегистрированных элементах и т.п.

+ +

Чтобы зарегистрировать пользовательский элемент на странице, используйте метод {{domxref("CustomElementRegistry.define()")}} method. Он принимает аргументы:

+ + + +

К примеру, мы можем определить пользовательский элемент word-count element:

+ +
customElements.define('word-count', WordCount, { extends: 'p' });
+ +

Этот элемент называется word-count, объект соответствующего класса называется WordCount, и он наследует элементу {{htmlelement("p")}}.

+ +

Объект класса пользовательского элемента определяется с помощью синтаксиса классов ES 2015. Например, WordCount имеют следующую структуру:

+ +
class WordCount extends HTMLParagraphElement {
+  constructor() {
+    // Всегда первым делом вызывайте super() в конструкторе
+    super();
+
+    // Далее пишется функциональность элемента
+
+    ...
+  }
+}
+ +

Это простой пример, но его можно дополнить. Можно определить специальные lifecycle callbacks, которые будут вызваны в определенные моменты жизненного цикла элемента. Например, connectedCallback будет вызван, когда пользовательский элемент оказывается впервые встроен в DOM, а attributeChangedCallback вызывается, когда пользовательскому элементу добавляют, удаляют или изменяют какой-то аттрибут.

+ +

Подробнее об этом в секции {{anch("Using the lifecycle callbacks")}} ниже.

+ +

Есть два типа пользовательских элементов:

+ + + +

Разбор простых примеров

+ +

А сейчас давайте разберем еще несколько простых примеров, иллюстрирующих подробности создания пользовательских элементов.

+ +

Автономные пользовательские элементы

+ +

Рассмотрим пример автономного пользовательского элемента — <popup-info-box> (см. работающий пример). Он содержит изображение и строку, и встраивает изображение в страницу. Когда на изображение наводят фокус, компонент показывает всплывающую подсказку с текстом.

+ +

Прежде всего файл JavaScript определяет класс PopUpInfo, наследующий от {{domxref("HTMLElement")}}. Автономные пользовательские элементы почти всегда наследуют HTMLElement.

+ +
class PopUpInfo extends HTMLElement {
+  constructor() {
+    // Всегда первым делом вызывайте super() в конструкторе
+    super();
+
+    // далее следует функциональность элемента
+
+    ...
+  }
+}
+ +

В этом фрагменте кода содержится определение конструктора {{jsxref("Classes.constructor","constructor")}} класса, которое всегда начинается с вызова super() чтобы отработала цепочка прототипного наследования.

+ +

Внутри конструктора мы определяем всю функциональность, которую получит элемент при создании его объекта. В данном случае мы добавляем shadow root к пользовательскому элементу, производим манипуляции с DOM, чтобы создать определенную структуру shadow DOM внутри элемента — которая затем присоединяется к shadow root — и наконец добавляем CSS к shadow root, чтобы задать его стиль.

+ +
// Создание 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);
+ +

Наконец, регистрируем пользовательский элемент в CustomElementRegistry с помощью метода define(), который упоминался ранее — в качестве параметров мы передаем ему имя элемента и имя класса, который содержит его функциональность:

+ +
customElements.define('popup-info', PopUpInfo);
+ +

Теперь он доступен для использования на нашей странице. В HTML мы используем его так:

+ +
<popup-info img="img/alt.png" text="Код валидации вашей карты (CVC)
+  это дополнительная мера безопасности — это последние 3 или 4 цифры
+  на обороте вашей карты.">
+ +
+

Замечение: Вы можете прочитать полный исходный код на JavaScript здесь.

+
+ +

Модифицированные встроенные элементы

+ +

Тепреь давайте взглянем на другой пример модифицированного пользовательского элемента — раскрывающийся список (см. действующий пример). Он превращает любой ненумерованный список в раскрывающееся/складывающееся меню.

+ +

Первым делом определим класс элемента наподобие того, как это делалось выше:

+ +
class ExpandingList extends HTMLUListElement {
+  constructor() {
+    // Всегда первым делом вызываем super() в конструкторе
+    super();
+
+    // ниже следует функциональность элемента
+
+    ...
+  }
+}
+ +

Здесь мы не будем во всех подробностях описывать функциональность элемента, вы можете понять как он работает, посмотрев исходный код. Единственное принципиальное различие с предыдующим примером состоит в том, что мы используем интерфейс {{domxref("HTMLUListElement")}}, а не {{domxref("HTMLElement")}}. Так что у него есть все характеристики элемента {{htmlelement("ul")}}, плюс дополнительная функциональность, которую определили мы. Это и отличает модифицированный встроенный элемент от автономного пользовательского элемента.

+ +

Далее мы регистрируем этот элемент с помощью метода define() как в прошлом примере, только на сей раз мы добавляем объект options, который определяет, какому встроенному элементу наследует данный:

+ +
customElements.define('expanding-list', ExpandingList, { extends: "ul" });
+ +

Встроенный элемент используется на веб-странице немного по-другому:

+ +
<ul is="expanding-list">
+
+  ...
+
+</ul>
+ +

Вы задаете элемент <ul> как обычно, но указываете имя модифицированного элемента в атрибуте is.

+ +
+

Замечание: Полный исходный код на JavaScript доступен здесь.

+
+ +

Использование lifecycle callbacks

+ +

Вы можете определить несколько разных коллбеков в конструкторе пользовательских элементов, которые сработают на разных этапах жизненного цикла элемента:

+ + + +

Посмотрим на них в действии. Код ниже взят из примера life-cycle-callbacks (см. его в действии). Это тривиальный пример, создающий на странице цветной квадрат. Вот как выглядит код пользовательского элемента:

+ +
<custom-square l="100" c="red"></custom-square>
+ +

Конструктор класса очень простой — мы просто добавляем shadow DOM к элементу, а затем добавляем пустые элементы {{htmlelement("div")}} и {{htmlelement("style")}} к shadow root:

+ +
var shadow = this.attachShadow({mode: 'open'});
+
+var div = document.createElement('div');
+var style = document.createElement('style');
+shadow.appendChild(style);
+shadow.appendChild(div);
+ +

Наиболее важная функция в этом примере updateStyle() — она принимает элемент, находит его shadow root, находит его элемент <style>, и добавляет {{cssxref("width")}}, {{cssxref("height")}}, и {{cssxref("background-color")}} к стилям.

+ +
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');
+    }
+  }
+}
+ +

Сами изменения стилей обрабатываются коллбеками жизненного цикла, находящимися внутри конструктора. connectedCallback() срабатывает, когда элемент встраивается в DOM — здесь мы запускаем функцию updateStyle() которая обсеспечивает, чтобы квадрат имел стиль, описанный в его атрибутах:

+ +
connectedCallback() {
+  console.log('Пользовательский элемент квадрат добавлен на страницу.');
+  updateStyle(this);
+}
+ +

коллбеки disconnectedCallback() и adoptedCallback() логируют простые сообщения на консоль, которые уведомляют нас, что элемент удален из DOM или перемещен на другую страницу:

+ +
disconnectedCallback() {
+  console.log('Пользователский элемент квадрат удален.');
+}
+
+adoptedCallback() {
+  console.log('Пользовательский элемент квадарат перемещен на другую страницу.');
+}
+ +

Коллбек attributeChangedCallback() запускается когда один из аттрибутов элемента меняется. Как видно из его свойств, можно воздействовать на индивидуальные аттрибуты, глядя на их имена, и новые и старые значения аттрибутов. В данном случае, однако, мы просто снова запускаем функцию updateStyle() чтобы убедиться, что атрибуты квадрата получили новые значения:

+ +
attributeChangedCallback(name, oldValue, newValue) {
+  console.log('Атрибуты пользовательского элемента квадрат изменились.');
+  updateStyle(this);
+}
+ +

Обратите внимание, что нужно наблюдать за атрибутами, чтобы запустить коллбек attributeChangedCallback() когда они изменятся. Это делается через вызов геттера observedAttributes() в конструкторе, который содержит оператор return возвращающий массив с именами атрибутов, которые вы хотите наблюдать:

+ +
static get observedAttributes() {return ['w', 'l']; }
+ +

В нашем случае он расположен в начале конструктора.

+ +
+

Замечение: Смотрите полный исходный код на JavaScript здесь.

+
-- cgit v1.2.3-54-g00ecf