Ваш первый веб-компонент
Очень простой пример
Начнём с самого распространённого и часто используемого примера: кнопки счётчика.
<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 с этим примером.
Сохранение данных состояния
Необходимо отслеживать количество (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 с этим примером.
Обновление состояния и пользовательского интерфейса
Теперь мы готовы обновить 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`;
}
Обратите внимание, что каждый button
имеет своё собственное состояние. Клик по одному из них не влияет на счётчик другого.
Обеспечение доступности
Необходимо также сообщить об обновлении пользовательского интерфейса для устройств чтения с экрана.
Внутри constructor()
добавим атрибут [aria-live]
со значением polite
к this.button
.
/**
* Конструктор класса
*/
constructor () {
// ...
// Прослушивание события click
this.button.addEventListener('click', this);
// Объявление об обновлении UI
this.button.setAttribute('aria-live', 'polite');
}
Что дальше
Позже мы рассмотрим, как добавить опции и настройки в веб-компоненты, чтобы сделать их более гибкими.
Рассмотрим, как создать это с помощью традиционной библиотеки JavaScript, чтобы вы могли увидеть разницу. На мой взгляд, веб-компоненты значительно упрощают процесс создания (как для создателя, так и для того, кто ими пользуется).
- Создание веб-компонента с нуля
- В чём разница между Virtual DOM и Shadow DOM
- Создание меню "вне холста" с
<dialog>
и веб-компонентами
Все статьи серии о Веб-Компонентах/Web Component
- Ваш первый веб-компонент
- Добавление опций в веб-компонент
- Улучшение веб-компонента
- Различные способы инстанцирования веб-компонента
- Методы жизненного цикла веб-компонента
- Как обнаружить изменение атрибутов веб-компонента
- Как заставить веб-компоненты общаться (часть 1)
- Как заставить веб-компоненты общаться (часть 2)