Как заставить веб-компоненты общаться (часть 1)

Источник: «How to get different Web Components to talk to each other (part 1)»
Меня спрашивали, как вложить веб-компоненты друг в друга и передавать информацию от одного к другому. Сегодня мы рассмотрим, как это реализовать.

Глупый веб-компонент

Для этой статьи создадим довольно бессмысленный веб-компонент <wc-highlight>.

<wc-highlight>
<div>1</div>
<div>2</div>
<div>3</div>
</wc-highlight>

Когда веб-компонент инстанцируется, он…

  1. Получает всех непосредственных потомков .children внутри себя.
  2. Устанавливает первый элемент в этом списке (с индексом 0) в качестве активного active.
  3. Выделите первый элемент в коллекции, установив [aria-selected='true'].
customElements.define('wc-highlight', class extends HTMLElement {

/**
* Создание элемента
*/

constructor () {

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

// Определяем свойства
this.boxes = Array.from(this.children);
this.active = 0;

// Устанавливаем [aria-selected]
// Если первый элемент, устанавливаем в true
// Иначе, устанавливаем в false
this.boxes.forEach(function (box, index) {
box.setAttribute('aria-selected', index === 0 ? true : false);
});

}

});

Также в веб-компоненте есть метод .next().

Он увеличивает значение this.active на 1 (и сбрасывает его на 0, когда достигает конц списка). Затем он обновляет атрибут [aria-selected], чтобы выделить новый элемент.

/**
* Перейти к следующему элементу
*/

next () {

// Кэшируем активный, в данный момент, индекс
let current = this.active;

// Обновляем активный индекс
this.active++;

// Если это конец, возвращаемся к началу.
if (this.active === this.boxes.length) {
this.active = 0;
}

// Обновляем [aria-selected]
this.boxes[current].setAttribute('aria-selected', false);
this.boxes[this.active].setAttribute('aria-selected', true);

}

Запустив его на элементе <wc-highlight>, можно перенести выделение с текущего элемента на следующий в списке.

let highlight = document.querySelector('wc-highlight');
highlight.next();

See the Pen

Вкладываем веб-компонент внутрь него

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

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

В целях обучения создадим элемент <wc-highlight-controls> внутри constructor() веб-компонента <wc-highlight> и внедрим его в DOM.

/**
* Создание элемента
*/

constructor () {

// ...
this.boxes.forEach(function (box, index) {
box.setAttribute('aria-selected', index === 0 ? true : false);
});

// Append controls
let controls = document.createElement('wc-highlight-controls');
this.append(controls);

}

Затем можно определить <wc-highlight-controls> как отдельный веб-компонент.

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

/**
* Создание элемента
*/

constructor () {

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

// Код компонента...
}

});

Внутри constructor() можно использовать метод Element.closest(), для получения родительского элемента <wc-highlight>, и присвоить его this.highlight.

Если родительский элемент не найден, завершаем выполнение с помощью return.

/**
* Создание элемента
*/

constructor () {

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

// Получаем родительский элемент <wc-highlight>
this.highlight = this.closest('wc-highlight');
if (!this.highlight) return;

Далее создадим элемент button, зададим ему текст и .append() его внутри веб-компонента.

Затем добавим к нему слушателя события click.

/**
* Создание элемента
*/

constructor () {

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

// Получаем родительский элемент <wc-highlight>
this.highlight = this.closest('wc-highlight');
if (!this.highlight) return;

// Создаём кнопку button
this.button = document.createElement('button');
this.button.textContent = 'Next';
this.append(this.button);

// Слушаем событие clicks для кнопки button
this.button.addEventListener('click', this);

}

Внутри метода handleEvent() запускаем метод .next() на this.highlight, для перехода к следующему элементу.

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

handleEvent (event) {
this.highlight.next();
}

See the Pen

Это очень простое подключение

Этот метод основан на тесном взаимодействии элементов DOM.

Он работает, но может быть ненадёжным, поскольку зависит от того, что определённые элементы загружаются в правильном порядке и всегда имеют доступ друг к другу.

Завтра рассмотрим предпочитаемый мною метод: Пользовательские события / Custom Events.

Они дают возможность настраивать веб-компоненты и обмениваться данными более гибким и независимым способом.

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

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

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

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

Как обнаружить изменение атрибутов веб-компонента

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

Как заставить веб-компоненты общаться (часть 2)