Ваш первый веб-компонент

Источник: «Your first Web Component»
Давайте рассмотрим, как создать свой первый веб-компонент.

Очень простой пример

Начнём с самого распространённого и часто используемого примера: кнопки счётчика.

<button>Clicked 0 Times</button>

Когда пользователь кликает на кнопку, необходимо её обновить, чтобы отобразить количество раз, сколько раз на неё кликнули.

Определение веб-компонента

Для начала обернём button в элемент wc-count.

<wc-count>
<button>Clicked 0 Times</button>
</wc-count>

Далее воспользуемся методом customElements.define(), чтобы определить элемент и передать в JavaScript класс для обработки его поведения.

При использовании веб-компонента класс всегда расширяет класс HTMLElement. Это позволяет унаследовать всё нормальное поведение HTML-элемента.

customElements.define('wc-count', class extends HTMLElement {
// ...
});

Далее создадим метод constructor() для инициализации класса на нашем элементе.

Внутри constructor() необходимо сначала запустить метод super(). Это позволит экземпляру автоматически наследовать все свойства родительского класса, HTMLElement.

customElements.define('wc-count', class extends HTMLElement {

/**
* Конструктор класса
*/

constructor () {

// Всегда вызывайте super первым в конструкторе
super();

// Теперь мы в деле!
console.log(this);

}

});

Как только это будет загружено на страницу, наш новый класс будет автоматически инстанцировать каждый элемент <wc-count> на странице как уникальный экземпляр.

В этом примере данные выводятся в консоль. Можно включить панель Инспектор и перейти во вкладку консоль и увидеть результат выполнения скрипта там. Или перейти на сайт CodePen с этим примером.

See the Pen

Сохранение данных состояния

Необходимо отслеживать количество (count) кликов по кнопке (button).

Добавим свойство this.button, хранящее элемент button. В нашем классе this это элемент wc-count. Можно использовать метод Element.querySelector(), чтобы найти button внутри него.

Также добавим свойство this.count со значением по умолчанию 0.

/**
* Конструктор класса
*/

constructor () {

// Всегда вызывайте super первым в конструкторе
super();

// Свойства экземпляра
this.button = this.querySelector('button');
this.count = 0;

}

Это не реактивное состояние, как в компонентах React. Обновление значения this.count не приводит к какому-либо автоматическому обновлению пользовательского интерфейса.

Это просто удобный способ хранения данных, уникальных для каждого элемента wc-count.

Добавление интерактивности

Когда this.button нажимается, необходимо обновить this.count, а затем обновить текст в this.button, чтобы отразить новое значение.

Давайте добавим слушателя события click к this.button. Передадим его в качестве второго аргумента вместо метода обратного вызова. Я объясню, почему, через секунду.

/**
* Конструктор класса
*/

constructor () {

// Всегда вызывайте super первым в конструкторе
super();

// Свойства экземпляра
this.button = this.querySelector('button');
this.count = 0;

// Прослушивание события click
this.button.addEventListener('click', this);

}

Если прослушивать событие с помощью метода addEventListener(), то в качестве второго аргумента можно передавать не функцию обратного вызова, а объект.

Пока у этого объекта есть метод handleEvent(), событие будет передано в него, но при этом сохранится привязка к объекту.

В наш класс можно добавить метод handleEvent(), позволяющий обрабатывать событие click, но при этом обеспечивающий лёгкий доступ к экземпляру (this), чтобы можно было обращаться к this.button и this.count.

customElements.define('wc-count', class extends HTMLElement {

/**
* Конструктор класса
*/

constructor () {
// ...

// Прослушивание события click
this.button.addEventListener('click', this);

}

/**
* Обработка событий
* @param {Event} event Объект события
*/

handleEvent (event) {
console.log('clicked!', this);
}

});

В этом примере данные выводятся в консоль. Можно включить панель Инспектор и перейти во вкладку консоль и увидеть результат выполнения скрипта там. Или перейти на сайт CodePen с этим примером.

See the Pen

Обновление состояния и пользовательского интерфейса

Теперь мы готовы обновить this.count и текст внутри this.button.

Внутри метода handleEvent() увеличим this.count на 1 с помощью оператора инкремента (++). Затем мы обновим textContent внутри this.button.

/**
* Обработка событий
* @param {Event} event Объект события
*/

handleEvent (event) {
this.count++;
this.button.textContent = `Clicked ${this.count} Times`;
}

See the Pen

Обратите внимание, что каждый button имеет своё собственное состояние. Клик по одному из них не влияет на счётчик другого.

Обеспечение доступности

Необходимо также сообщить об обновлении пользовательского интерфейса для устройств чтения с экрана.

Внутри constructor() добавим атрибут [aria-live] со значением polite к this.button.

/**
* Конструктор класса
*/

constructor () {
// ...

// Прослушивание события click
this.button.addEventListener('click', this);

// Объявление об обновлении UI
this.button.setAttribute('aria-live', 'polite');

}

See the Pen

Что дальше

Позже мы рассмотрим, как добавить опции и настройки в веб-компоненты, чтобы сделать их более гибкими.

Рассмотрим, как создать это с помощью традиционной библиотеки JavaScript, чтобы вы могли увидеть разницу. На мой взгляд, веб-компоненты значительно упрощают процесс создания (как для создателя, так и для того, кто ими пользуется).

Все статьи серии о Веб-Компонентах/Web Component

Дополнительные материалы

Предыдущая Статья

Копирование файлов между Docker контейнером и хостом

Следующая Статья

Добавление опций в веб-компонент